개발 공부/안드로이드

recyclerview 더 효율적으로 사용하기 - ListAdapter와 DiffUtil

yong_DD 2022. 7. 3. 16:05

기존에 reyclerview의 adapter를 만드려면 Reyclerview.Adapter을 사용해왔다.

해당 방식을 사용하려면 어뎁터 내의 리스트도 관리를 해야했고 데이터를 넣거나 변경, 삭제하는 등이 변화가 있을 경우 일일이 변경처리를 해야했다.

(notifyItemInserted(), notifyItemRemoved(), notifyItemRangeChanged().....)

변동이 있어 전체 내역을 업데이트 해야해서 내역을 삭제하고 다시 불러오는 경우, 몇 개만 변동되는데 전체를 업데이트 하다보니 지연시간이 있을 수 밖에 없고 그만큼의 불필요한 비용도 생기게 된다.

이러한 비용을 줄이고자 나온게 DiffUtil 이고, 이 DiffUtil을 활용해 리스트를 업데이트 시키는 기능을 가진 것이 ListAdapter이다.

 


1. DiffUtil

가지고 있는 데이터(과거 데이터)와 바꿀 데이터(새로운 데이터)를 비교해서 변경되어야할 데이터만 변경해준다.

 

콜백을 정의해준다. ( 두 항목 간의 차이를 계산하기 위한 콜백)

val callback = object : DiffUtil.ItemCallback<모델>(){
            override fun areItemsTheSame(oldItem: 모델, newItem: 모델): Boolean {
                // 동일한 항목을 나타내는지 - 해당 아이템이 고유 id 값을 가지고 있다면 그걸로 기준 
                return oldItem.id == newItem.id
            }
            override fun areContentsTheSame(oldItem: 모델, newItem: 모델): Boolean {
                // 동일한 데이터를 가지고 있는지 
                return oldItem == newItem
            }
        }

 

2. ListAdapter

기존의 diffUtil은 recyclerView.Adapter에서 사용할 때 아이템이 많으면 시간이 많이 소요될 수 있으므로 비동기 처리를 해야했었다. 그걸 자체적으로 비동기 처리해주던 AsyncListDiffer의 wrapper 클래스로 더욱 간소하고 간편하게 사용하게 만들어주는 클래스다.

2-1 ListAdapter에 콜백을 달아준다.

class TestAdapter : ListAdapter<Test,TestAdapter.TestItemViewHolder>(diffUtil) {
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestItemViewHolder {
        return TestItemViewHolder(ItemTestBinding.inflate(LayoutInflater.from(parent.context),parent,false))
    }

    override fun onBindViewHolder(holder: TestItemViewHolder, position: Int) {
        holder.bind(currentList[position])
    }


    inner class TestItemViewHolder(private val binding : ItemTestBinding):RecyclerView.ViewHolder(binding.root){
        fun bind(test:Test){
          ...
        }
    }

   companion object{
     val diffUtil = object : DiffUtil.ItemCallback<Test>(){
            override fun areItemsTheSame(oldItem: Test, newItem: Test): Boolean {
                // 동일한 항목을 나타내는지 - 해당 아이템이 고유 id 값을 가지고 있다면 그걸로 기준 
                return oldItem.id == newItem.id
            }
            override fun areContentsTheSame(oldItem: Test, newItem:Test): Boolean {
                // 동일한 데이터를 가지고 있는지 
                return oldItem == newItem
            }
        }
    }
}

 

2-2 해당 adapter에 submitList (List<T> list) 통해 새로운 리스트를 전달해준다.

val adapter = TestAdapter()
adapter.submitList(해당 리스트)

이렇게 간단하게 코드도 줄고 효율적으로 recyclerview를 사용할 수 있다!

 

 

 

[참고자료]