📱 Android

[Android / RecyclerView] onCreateViewHolder vs onBindViewHolder: 클릭 리스너는 어디에 둘까?

콩드로이드 2025. 4. 7. 21:42

🎯 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을 가져오기 때문에 더 안전한 방법입니다