Stand up lee

[Kotlin] error : Recyclerview 스크롤시 Checkbox checked 에러 본문

개발일기

[Kotlin] error : Recyclerview 스크롤시 Checkbox checked 에러

tubeeee 2022. 3. 30. 01:38

kotlin으로 GridLayoutManager로 Checkbox 가 담긴 아이템 리스트들을 나열하였다.

이때, 체크박스로 선택한 set들을 다음 화면에 전달해야하는데, 스크롤을 내렸을 때 원하지 않는 체크박스가 저절로 선택되어 있는 문제가 생긴 것

이건 Recyclerview 재활용 로직때문에 발생하게 된 것이라고한다.
Recyclerview는 데이터의 모든 아이템에 해당하는 뷰를 할당하지 않는다. 화면에 맞는 아이템 뷰의 수만 할당하고 사용자가 스크롤할 때 해당 아이템 레이아웃을 재활용하는 것이다. 
즉, Adapter가 내가 표시한 아이템 뷰를 스크롤했을때 보이게 되는 다음 뷰에 복사를 하게 되는 것이다.
그래서 내가 앞에서 체크박스를 선택하면 이 뷰가 복사되어 다음 뷰에도 나타나게 된다는 것.

 

그래서 일단 다음과 같은 방법으로 문제를 해결했다.

해결방안

fun getCheckedHead(): HashSet<String?> {
	return mCheckedHead
}


inner class ViewHolder(itemView : View): RecyclerView.ViewHolder(itemView){
        var theme : CheckBox
        var head : TextView
        var count : TextView

        init{
            theme = itemView.findViewById(R.id.cb_quiztheme)
            head = itemView.findViewById(R.id.tv_head)
            count = itemView.findViewById(R.id.tv_count)
            
            theme.setOnCheckedChangeListener { _, isChecked ->
                val head = dataList[adapterPosition].head
                if(isChecked) mCheckedHead.add(head)
                else{
                    mCheckedHead.remove(head)
                }

            }
        }
    }

일단 체크한 아이템을 담는 hashset을 선언한 후
inner class viewholder에 checkbox를 선택했을 때 check되면 set에 담는다.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val data = dataList[position]

        holder.theme.text = data.theme
        holder.head.text = data.head
        holder.count.text = data.count

        holder.theme.isChecked = mCheckedHead.contains(data.head)

}

그 다음 아래에서 뷰홀더에 바인딩을 할 때, checkbox를 담은 set에 아이템이 들어있는지 확인하는 코드만 추가하여 해결하였다.

(해결방안이 쉬운데,, 이걸 생각하기까지 오래걸림...;; 더 나은 방식을 찾게 되면 수정해야겠다)