[ 안드로이드 - 코틀린 ] DiffUtil 사용기 (ListAdapter)

2023. 3. 21. 14:53Android

기본적으로 RecyclerView를 사용할 때는 RecyclerView.Adapter를 이용하고 notifyDataSetChanged()를 이용해 화면 UI를 갱신하는 형태로 진행했었다. 이유라면 구현이 쉽기도 하고 그냥 잘 몰라서였다.

 

notifyDataSetChanged() 비효율적인 이유는 해당 메서드를 이용하면 데이터를 변경할 때마다 모든 아이템들을 다시 그리기 때문에 비효율적인 갱신 방법이다. 하지만 사용하기 쉽게 때문에 많이 이용했다. 지금까지는.... 

 

이번에 새로 사용해본 DiffUtil을 이용한다면 보다 효율적으로 아이템들을 갱신할 수 있다.

DiffUtil은 최소한의 데이터를 이용해 데이터들을 업데이트하기 때문에 효율적인 방법인 데이터 갱신 방법이다.

 

+ 하지만 이러한 작업이 오래걸리는 경우 백그라운드에서 실행하는 것이 옳다 -> 연산이 오래걸려서 

 

DiffUtil 메소드들

 

class UserDiffCallback : DiffUtil.ItemCallback<User>(){
    override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
        return oldItem.uid == newItem.uid
    }

    override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
        return oldItem == newItem
    }
}

 

areItemsTheSame

두 아이템들을 비교해 같은 객체인지 확인하다고 반환한다.

 

areContentTheSame

두 아이템이 같은 데이터를 가지고 있는지 확인하고 반환한다. areItemsTheSame에서 true를 반환할 때만 호출이 된다. 왜냐면 위에서 같은 객체인지 확인을 하고 다르다면 호출해 비교할 필요가 없기 때문이다.

 

 

하단 코드는 ListAdapter로 구현한 UiffUtil 코드이다.

DB에 데이터가 저장되면 객체 아이디 값을 비교해 객체에 다른 부분이 있다면 새로 갱신에 나타내준다.

class UserAdapter : ListAdapter<User, UserAdapter.MyViewHolder>(UserDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val view: View = inflater.inflate(R.layout.list_item, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val user = getItem(position)
        holder.bind(user)
    }

    inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val nameText: TextView = itemView.findViewById(R.id.name_text)
        private val ageText: TextView = itemView.findViewById(R.id.age_text)

        fun bind(user: User) {
            nameText.text = user.userName
            ageText.text = user.userAge
        }
    }

    class UserDiffCallback : DiffUtil.ItemCallback<User>(){
        override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
            return oldItem.uid == newItem.uid
        }

        override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
            return oldItem == newItem
        }

    }
}

 

앞으로 recyclerView를 이용해 데이터를 나타내줄 때 유용하게 사용할 생각이다. 새로운 방식에 적응하느라 시간이 조금 걸렸지만 효율적인 방법이기에 사용해볼 예정이다