다음은 프로젝트 진행에 있어 문제 해결에 많은 어려움을 겪었던 코드이다.

class PicturesAdapter() : RecyclerView.Adapter<PictureViewHolder>() {
    private lateinit var itemBinding: ItemPhotoCheckingBinding
    private val pictures : ArrayList<Uri> = ArrayList()


    inner class PictureViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
        fun bind(pos : Int){
            val targetUri = pictures[pos]
            GlideApp.with(itemView.context)
                .load(targetUri)
                    .into(itemBinding.photo)
            itemBinding.clearBtn.setOnClickListener {
                removeItem(targetUri)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PictureViewHolder {
        itemBinding = ItemPhotoCheckingBinding.inflate(LayoutInflater.from(parent.context))
        return PictureViewHolder(itemBinding.root)
    }

    override fun getItemCount(): Int {
        return pictures.size
    }

    override fun onBindViewHolder(holder: PictureViewHolder, position: Int) {
        holder.bind(position)
    }


    private fun removeItem(targetUri :Uri){
        val pos = pictures.indexOf(targetUri)
        pictures.removeAt(pos)
        notifyItemRemoved(pos)
    }

    fun addPicture(uri : Uri){
        pictures.add(0,uri)
        notifyItemInserted(0)
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

처음에는 bind(pos : Int) 시에 position이 fix 되어 문제가 발생한다고 생각하였다.

absoluteAdapterPosition, bindingAdapterPosition 등을 사용하여 해결하려 했으나 문제는 viewBinding에 있었다.

 

해당 코드를 살펴보면 onCreateViewHolder에서 바인딩 인스턴스를 생성하여 root 레이아웃을 itemView로 건네고 있습니다.여기까진 문제가 없을 수 있으나 itemView 내부의 view ( photo, clearBtn ) 에 대해서 onCreateViewHolder에서 생성한 동일한 바인딩 객체에 참조 하는 것을 확인할 수 있습니다. RecyclerView의 목적처럼 뷰홀더를 재사용하는것이 불가능해집니다.

 

해결책

1. itemView를 넘기는 기존의 방식을 사용하여 해결 (findViewByID) -  viewbinding을 사용하는 의미가 퇴색됨

    inner class PictureViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            fun bind(pos : Int){
                val _photo = itemView.findViewById<ImageView>(R.id.photo)
                val _clearBtn = itemView.findViewById<ImageView>(R.id.clearBtn)

                val targetUri = pictures[pos]
                GlideApp.with(itemView.context)
                    .load(targetUri)
                    .into(_photo)
                _clearBtn.setOnClickListener {
                    imageManager.deleteImage(targetUri)
                    removeItem(targetUri)
                }
            }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PictureViewHolder {
        itemBinding = ItemPhotoCheckingBinding.inflate(LayoutInflater.from(parent.context))
        return PictureViewHolder(itemBinding.root)
    }

 

 

2. viewBinding을 활용한 ViewHolder 사용 ( 권장 )

    inner class PictureViewHolder(private val itemBinding: ItemPhotoCheckingBinding) : RecyclerView.ViewHolder(itemBinding.root){
        fun bind(pos : Int){
            val targetUri = pictures[pos]
            GlideApp.with(itemView.context)
                .load(targetUri)
                    .into(itemBinding.photo)
            itemBinding.clearBtn.setOnClickListener {
                imageManager.deleteImage(targetUri)
                removeItem(targetUri)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PictureViewHolder {
        itemBinding = ItemPhotoCheckingBinding.inflate(LayoutInflater.from(parent.context))
        return PictureViewHolder(itemBinding)
    }

+ Recent posts