[Android, Kotlin] RecyclerView 내부 Do not treat position as fixed; only use immediately and call holder.getAdapterPosition() to look it up later 문제 해결

 

[문제 상황]

 

코틀린으로 한 달 주기 앱을 개발 중이었다.

리싸이클러 뷰에서 item을 클릭하면 작은 팝업창이 떠서 icon을 선택할 수 있고,

icon을 선택하면 다시 리싸이클러 뷰로 돌아와서 해당 icon으로 변경하는 방식의 코드를 작성 중이였다.

 

Do not treat position as fixed; only use immediately and call holder.getAdapterPosition() to look it up later

 

오류가 발생했다.

 

직역하면 position을 고정된 값으로 생각하지 말라는 것이고 즉시 사용해야하며 홀더에서 호출하라는 뜻이었다.

개발문서에서 관련 문제를 찾아보았다.

 

RecyclerView.ViewHolder  |  Android Developers

 

RecyclerView.ViewHolder  |  Android Developers

Stay organized with collections Save and categorize content based on your preferences. RecyclerView.ViewHolder This package is part of the Android support library which is no longer maintained. The support library has been superseded by AndroidX which is p

developer.android.com

 

관련 문서

developer 공식 문서를 찾아보니 다른 Listener 안에서는

positon 대신 holder.getAdapterPosition()을 적용하라는 것 같았다.

 

[문제 해결]

 

일단 오류가 발생한 위치를 살펴보았다.

 

override fun onBindViewHolder(holder: ToDoCalendarViewHolder, position: Int) {
    holder.binding.calendarItemText.text = dataSet[position].text
    holder.binding.calendarItemIcon.setImageResource(calendarIcon[dataSet[position].iconType])

    //icon 변경
   holder.binding.calendarItemIcon.setOnClickListener {
       val dig = SelectIconDialog(mainActivity)
       dig.showDig()

       dig.setOnClickedListener(object :SelectIconDialog.ButtonClickListener{
           override fun onClicked(index: Int?) {
               if (index!=null){
                   onClickChangeIcon.invoke(dataSet[position],index)
               }
           }

       })
    }

 

공식 문서에서는 ViewHolder 내부에서  다른 Listener안에서

position을 적용할 때 position 값을 그대로 적용하지 않는게 좋다고 했다.

 

onClickChangeIcon.invoke(dataSet[position],index)

 

Dialog 사용 시 Dialog 내부에 인터페이스로 클릭 이벤트를 선언하고 이를 외부에서 사용하는 방식을 썼다.

이후에 변경될 값을 index로 받아와서 dataSet에 적용시켜주는 코드였다.

dataSet 내부의 position의 사용 방법을 변경 해야했다.

 

공식 문서의 getAdapterPosition()이 Deprecated 되었다고 한다.

이유는 Adapter가 다른 Adapter를 중첩하는 경우 어떤 Adapter의 위치인지 혼란스럽다는 이유이다..

 

잘 모르겠지만 다른 해결 방법을 찾아보았다.

 

2가지 해결 방법을 찾았다.

 

1. getBindingAdapterPosition() 사용 : Adapter 내의 포지션 반환

2. getAbsoluteAdapterPosition() 사용 : RecyclerView 내의 포지션 반환

 

두 메서드 모두 같은 position 값을 반환하기에 첫번째 방법을 사용했다.

 

//onClickChangeIcon.invoke(dataSet[position],index)를 아래 코드로 변경

onClickChangeIcon.invoke(dataSet[holder.bindingAdapterPosition],index)

 

문제를 해결했다!