RecyclerView에 DiffUtil을 사용해 보자

김흰돌·2023년 2월 3일
0

RecyclerView

목록 보기
2/4

RecyclerView에 데이터가 변화될 때?

RecyclerView를 사용하다 데이터의 변화가 있을 때 리스트를 업데이트하는 5가지 방법이 있다.

notifyDataSetChanged - 리스트 전체 업데이트
notifyItemChanged, notifyItemRangeChanged - 특정 범위의 아이템만 변경
notifyItemInserted, notifyItemRangeInserted - 특정 위치에 아이템 새로 추가
notifyItemRemoved, notifyItemRangeRemoved - 특정 범의의 아이템 삭제
notifyItemMoved - 아이템 위치 이동

위의 기능들을 활용하여 RecyclerView를 유용하게 사용할 수 있다.

하지만 notifyDataSetChanged같은 경우는 리스트를 전부 지우고 처음부터 하나씩 view를 만들기 때문에 리소스가 굉장히 비효율적으로 사용 되는 단점이 있다.

그 외 다른 방법들도 리스트가 수정되는 케이스에 맞춰 적용하는 게 번거롭게 느껴진다.



DiffUtil이란?

DiffUtil은 이전 데이터와 현재 데이터를 비교하여 반드시 수정되어야 할 부분만 갱신하게 된다.

즉 번거롭게 리스트에 발생하는 케이스에 맞는 함수를 사용할 필요 없고, 데이터 업데이트도 최소한으로 하여 성능적인 부분에서도 큰 이점이 있다.



DiffUtil 적용

전에 작성했던 RecyclerView를 사용해 보자 프로젝트에 DiffUtil을 추가해보자

Diffutil 클래스 생성

class DiffUtilCallback(
    private val oldList: MutableList<RecyclerViewItem>,
    private val newList: MutableList<RecyclerViewItem>
) : DiffUtil.Callback() {

    // 이전 목록의 크기
    override fun getOldListSize(): Int = oldList.size

    // 변경된 목록의 크기
    override fun getNewListSize(): Int = newList.size

    /**
     * 두 객체가 같은 아이템인지 비교함
     * 보통 유니크 키 값을 사용하여 비교함
     * 현재 프로젝트에선 item의 title로 비교
     */
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
        oldList[oldItemPosition].title == newList[newItemPosition].title

    /**
     * areItemsTheSame 함수가 True이면 호출됨
     * 두 개의 아이템이 같은 데이터를 가지고 있는지 '=='를 통해 동등성을 비교함
     * 같은 아이템이라도 다른 값을 가지고 있는 경우가 발생함
     */
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
        oldList[oldItemPosition] == newList[newItemPosition]

}

DiffUtil.Callback을 상속받고 오버라이딩 하여 함수를 사용하면 된다.
그리고 RecyclerViewAdapterDiffUtilCallback 객체를 생성해준다.

RecyclerViewAdapter.kt

private val itemList = mutableListOf<RecyclerViewItem>()

fun updateList(items: MutableList<RecyclerViewItem>) {
        val diffCallback = DiffUtilCallback(itemList, items)
        val diffResult = DiffUtil.calculateDiff(diffCallback)

        itemList.clear()
        itemList.addAll(items)

        diffResult.dispatchUpdatesTo(this)
    }

updateList 함수를 만들고 새로 들어온 데이터와 기존에 있던 데이터를 DiffUtilCallback 객체에 넣어준다.

DiffUtil.calculateDiff에 생성한 객체를 넣어준 후 diffResult.dispatchUpdatesTo(this)를 호출하게 되면 RecyclerView를 갱신할 수 있게 된다.

Git 주소

0개의 댓글