다음은 프로젝트 진행에 있어 문제 해결에 많은 어려움을 겪었던 코드이다.
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)
}
'Android > Feedback on Failures' 카테고리의 다른 글
<Refactoring> Retrofit과 데이터 모델 (0) | 2023.09.12 |
---|---|
<Refactoring> DTO 계층구조 (0) | 2023.09.11 |
<Refactoring> LiveData Observing (0) | 2023.09.10 |
ListAdapter의 submitList UI 반영 문제 (0) | 2023.08.15 |
RecyclerView Item 크기 조절 문제 (0) | 2023.08.11 |