🎯 RecyclerView 클릭 리스너, 어디서 설정하는 게 좋을까?
저는 원래 RecyclerView의 Adapter에 리스너를 설정할 때, 자연스레 onBindViewHolder()에서 뷰홀더로 넣어주는 방식을 많이 사용했었는데, 이게 성능과 메모리에 좋지 않다는 걸 알게 되었습니다 ,,!
일단, 2개의 호출 시점이 중요했습니다 !
🔁 호출 시점의 차이
onCreateViewHolder()
→ 새로운 뷰 홀더가 필요할 때 한 번만 호출
🔄 onBindViewHolder()
→ 뷰 홀더가 데이터와 바인딩될 때마다 반복적으로 호출
⚠️ 스크롤할 때마다 계속 호출됨
onBindViewHolder에서 리스너를 생성하게 된다면,
스크롤할 때마다 새로운 리스너 객체가 만들어지기 때문에 메모리 사용량이 증가되고 GC가 생성됩니다
따라서 재사용성을 향상시키고 메모리를 절약하기 위해선 onCreateViewHolder()에서 해주는 게 좋다고 합니다
소스를 예로 보자면,
class MyAdapter(
private val items: List<String>,
private val listener: OnClickListener
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
inner class MyViewHolder(private val binding: ItemLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
init {
// 클릭 리스너는 한 번만 설정
binding.root.setOnClickListener {
val position = bindingAdapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onClick(position)
}
}
}
fun bind(item: String) {
binding.textView.text = item
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.size
interface OnClickListener {
fun onClick(position: Int)
}
}
❓inner class 없이 onCreateViewHolder에서 바로 리스너를 설정하면 안 될까?
이론적으로는 가능하지만이 시점에서는 아직 뷰홀더가 어떤 데이터를 바인딩받을지 결정되지 않았기 때문에,
position 값이 유효하지 않을 수 있고 , 재사용 시 잘못된 position을 참조할 위험이 있습니다 ..!
즉, 예시 코드처럼 inner class의 ViewHolder에서 init {} 블록 안에서 bindingAdapterPosition을 사용하는 방식이
항상 최신 position을 가져오기 때문에 더 안전한 방법입니다
'📱 Android' 카테고리의 다른 글
[Android] 클린 아키텍처 적용 시 고민했던 3가지 의문점 (0) | 2025.04.12 |
---|---|
[Android] LiveData - observeForever (0) | 2025.03.21 |
[Android] ViewPager2 감도 조절하기 (0) | 2025.02.08 |
[Android] AAC의 LiveData, ViewModel의 LiveData (0) | 2025.02.04 |
[Android] binding 즉시 업데이트 하기 executePendingBindings (0) | 2024.11.21 |