리사이클러뷰에서 이벤트처리는 내부에서 하는 것이 아니라 콜백형태로 처리해서 결과를 외부에서 받아오는게 일반적인 처리방법입니다. 예를 뷰홀더에 있는 버튼클리이벤트를 처리하려고 하면, 버튼클릭 이벤트가 발생할 때, 이 이벤트를 어댑터를 통해 액티비티/프래그먼트로 전달하는 방식이 됩니다. 버튼 클래스가 setOnClickListener를 통해 View.OnClickListner를 처리하는 것과 같은 방식이라고 보면 됩니다.
다른 건 보지 마시고 먼저 어댑터와 액티비티 사이에 어떻게 콜백을 설정하고 처리하는지만 보시면 구조가 단순해 집니다.
public MyAdpater extends RecyclerView.Adaptger<MyViewHolder> {
interface Listener {
void onImageChcked(ImageInfo imageInfo):
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener.
}
}
보시다시피 Button.setOnClickListener를 호출하는 것과 똑같습니다. 다른 점은 실제 뷰에 대한 처리는 뷰홀더에서 하므로 Listener가 뷰홀더에 전달되어야 한다는 부분이죠. 이 분도 어댑터-뷰홀더로 좁혀놓고 보면 다른 클래스에 리스너를 설정하는 것과 똑같습니다. 결국 Button에 View.OnClickListener를 설정해서 사용하실 줄 알면, 코드를 조그만 더 주의 깊게 보시면, 이해가 갈 수 있는 부분입니다.
리사이클러뷰 어댑터에 대해서 알고 계셔야 하는 중요한 부분은 리사이클러뷰라는 이름그대로, 재활용을 한다는 겁니다. 즉, '뷰'를 재활용하는 겁니다. '뷰'는 뷰홀더에 존재하므로 결국 뷰홀더 오브젝트를 재활용하는 겁니다. 재활용 목적은 매번 클래스를 생성하는 것보다 재활용이 성능상 유리하기 때문입니다. 따라서 리사이클러뷰를 스크롤하게 되면 이전 생성되었던 뷰홀더가 재사용이 되므로, 뷰홀더에 있던 데이터도 남아 있게 됩니다. 따라서 뷰홀더에 멤버변수같은 것을 사용할 때는 주의를 해서 사용하셔야 합니다. 님의 경우는 리사이클러뷰를 스크롤하게 되면 i 변수가 엉뚱한 아이템의 버튼 상태를 가리키게 될 수가 있는거죠.
따라서 i변수는 사용하지 마시고 ImageInfo의 checked변수를 이용해서 리사이클러뷰를 업데이트 하세요. 아래와 같은 형태가 됩니다.
// Activity
private ImageAdapter imageAdapter;
private List<ImageInfo> dataSet;
// onCreate
dataSet = getImageData();
imageAdapter = new ImageAdapter(dataSet, new ImageAdapter.Listener() {
@Override
void onImageChcked(ImageInfo imageInfo) {
int index = dataSet.indexOf(imageInfo.getId());
imageInfo.setChecked(!imageInfo.isChecked());
dataSet.set(index, imageInfo);
imageAdapter.setDataSet(dataSet);
}
});
위처럼 어댑터의 데이터소스를 변경하여 어댑터를 업데이트 해주는 형태로 작성하세요.
시간내셔서 개발자가이드에서 리사이클러뷰를 어떻게 사용하는지 읽어보시기 바랍니다. 자주 사용하기 때문에 어느정도는 잘 알고 계셔야하는 뷰입니다.