본문 바로가기
Android 개발/RecyclerView, List

DiffUtil 이용해서 업데이트 하는 RecyclerView

by Developer88 2021. 4. 15.
반응형

오늘은 DiffUtil에 대해서 정리해 보도록 하겠습니다.

 

1. DiffUtil 과 notifyDataSetChanged

RecyclerView에 표현할 데이터를 업데이트하기 위해서 사용하는 것이 notifyDataSetChanged()라는 함수입니다.

표현할 데이터셋을 변경해주고 이것만 실행시키면 만사 오케이이기 때문인데요.

그런데, 뷰를 업데이트시키는 과정에서 비효율이 많이 발생합니다.

모든 데이터를 다시 그리기 때문인데요.

 

이를 개선하기위해, DiffUtil이 나왔습니다.

이것을 이용하면, 데이터들을 비교해서 변경된 부분만 효율적으로 업데이트 할 수 있습니다.

 

2. DiffUtil 구현

2-1. Adapter의 addAll

먼저 기존의 Adapter를 보겠습니다.

리스트에 뿌려줄 아이템들을 Activity에서 받아서 추가해 주는 것을 간단히 구현한다면,

아래와 같은 형식을 취했을 텐데요.

기존의 아이템들은 clear해 주어야 하므로 clear()함수를 사용했습니다.

 

 

하지만, DiffUtil은 기존의 리스트를 수정된 리스트와 비교해서 빠르게 업데이트 해 주는 클래스이므로,

이제 clear를 하지않고, DiffUtil을 이용해 주겠습니다.

 

2-2. DiffUtil클래스의 구현

먼저 DiffUtil.Callback을 상속받고 아래 두가지의 함수들을 구현해 주어야 합니다.

결국은 아이템간의 차이를 어떻게 구분할 것인지 알려달라는 것 이지요.

 

구분 내용
areItemsTheSame 두 객체가 같은 아이템인지를 비교합니다.
보통 유니크한 id값을 사용하는데요.
id가 없다면, 값이 유니크해서 비교할 수 있는 속성들을 사용해 줍니다..
areContentsTheSame areItemsTheSame이 True가 되면, 호출이 되는데요.
두개의 아이템이 같은 데이터를 가지고 있는지 체크하는 기준을 구현해야 하는 곳 입니다.

같은 아이템이라고 하더라도, 다른 값을 가지고 있는 경우가 발생할 수 있습니다.
보통 "=="으로 비교하게 됩니다

 

 

아래와 같이 간단하게 구현해 줄 수 있습니다.

 

private val mDiffCallback = object : DiffUtil.ItemCallback<Test>() {
    override fun areItemsTheSame(oldItem: Test, newItem: Test): Boolean {
       return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: Test, Test: SleepNight): Boolean {
       return oldItem.title == newItem.title
    }     
}

 

 

3. AsyncListDiffer

AsyncListDiffer는 백그라운드에서 두개의 리스트를 비교해서 변화를 감지해주는 API입니다.

 

private val mDiffer = AsyncListDiffer(this, mDiffCallback)

 

이제 Adapter로 리스트를 받아들여주는 함수만 만들어 주면 됩니다.

 

fun submitList(items: List<Test>) {
        mDiffer.submitList(items)
}

 

 

4. Adapter에서의 사용

onCreateViewHolder나 onBindViewHolder등 RecyclerView의 기본적인 구현은, recyclerView에대한 블로그글을 참조해 주시구요.

예전에는 List를 만들어서, Adapter에서 인자로 주는 position값으로 데이터를 찾아서 view를 구현하거나 했었는데요.

이제는 Adapter의 데이터에 접근할 때, mDiffer.currentList로 접근하는 것이 포인트입니다.

mDiffer를 이용해서 getItemCount()를 아래와 같이 구현해 줍니다.

 

override fun getItemCount(): Int = mDiffer.currentList.size

 

onBindViewHolder에서의 item도 이전에는 리스트에서 해당하는 position에 위치한 것을 찾았었는데요.

아래와 같이, mDiffer.currentList[position]으로 찾아 줍니다.

 

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val item = mDiffer.currentList[position]
    holder.binding.stringTitle = item.title
}

 

5. 정리

DiffUtil은 사용하기도 쉽고 매우 간단한 API이지만 필수가 된 API인 것 같네요.

addAll()하면서 생겼던 문제도 이 API를 사용하면서 해결된 적이 있구요.

더 좋은 방법이나 변경된 사항은 이 글을 통해서 업데이트하도록 하겠습니다.

 

728x90

댓글