[Kotlin] 안드로이드 recyclerView 클릭 리스너 달기 #onItemclickListener
recyclerView에서의 클릭 리스너 구현은 매번 까먹는다. 이 기회에 정리해보자.
1. 추상메서드
- 클릭시 caller에게 클릭되었다는 사실을 알려줄 종(bell)이 바로 이 추상메서드이다.
val onItemClickListener : ((Int)->Unit)? = null
- 람다식으로 구현했다. int 타입 하나를 매개변수로 받고 반환값이 없는 람다 함수이다.
*Unit은 java의 void와 같은 개념이다(return 값이 없음)
2. Item 클릭시 추상메서드 전달
- 이제 추상메서드를 사용해보자.
- item 클릭시 추상 메서드를 실행함으로써 이벤트를 처리한다.
- position만 넘겨주고 구체적인 동작은 Caller인 Activity에서 정의한다.
item.setOnClickListener{
var position: Int = item.tag as Int
onItemClickListener?.invoke(position)
}
*이때 해당 Item의 position을 넘겨줘야하는데 이를 위해서 binding 할때 tag를 지정해줘야한다.
override fun onBindViewHolder(holder: MovieListViewHolder, position: Int) {
holder.containerView.tag = getItemId(position)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
- getItemId는 아이템별로 Id를 부여해주는 adapter의 자체적인 추상메서드이다. 반환값이 Long으로 지정되어있다.
- onBindViewHolder에서 getItemId를 활용해 tag를 설정한다.
3. 추상메서드 내용 구체화
- caller인 Activity에서 클릭시 구현될 동작을 작성해주면 된다.
movieListAdapter.onItemClickListener = {
//원하는 내용 작성
}
------------------------------------------------------2020.05.04(월) 수정 -----------------------------------------------
adapter에서 position은 tag로 받았었는데 이는 불필요한 코드였다.
position은 viewholder에서 getAdapterPostion으로 받을 수 있기 때문에 이를 활용하는 것이 계산도 적게 들고 깔끔한 코드이다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieListViewHolder {
context = parent.context
val item = LayoutInflater.from(parent.context).inflate(R.layout.item_movie, parent, false)
val movieListViewHolder = MovieListViewHolder(item)
item.setOnClickListener {
var position = movieListViewHolder.adapterPosition
onItemClickListener?.invoke(position)
}
return movieListViewHolder
}
*onCreateViewHolder vs onBindViewHolder 어디에 listener를 달아줘야할까?
리사이클러뷰는 뷰홀더를 재활용하는 구조이기 때문에 뷰홀더 create는 한 화면에 들어갈 만큼만 만들어지지만 bind는 그 뷰홀더에 계속해서 새로운 데이터를 입히는 과정으로 스크롤로 자료가 변경될때마다 이루어진다.
onBindViewHolder는 뷰홀더에 데이터가 바인딩 될때마다 호출되는 method로 불필요한 listener 재생성이 이루어진다.
반면 onCreateViewholder는 뷰홀더를 만들때만 listener를 달아주면 되어 보다 효율적이다.