기존에 RecyclerView에서 데이터를 바꿀 때 매번 Adapter안에 setData() 메서드를 만들고 이 안에서 notifyDataSetChanged() 메서드를 호출하는 방식을 사용하였다. 하지만 이 방법은 데이터를 변경되지 않은 부분을 포함하여 전체를 다시 그리는 동작을 하기 때문에 데이터가 자주 바뀌는 환경에서 비용이 많이 든다는 단점이 있다.

ListAdapter를 사용하면 요소의 추가 및 삭제를 처리할 수 잇으며 변경사항에 애니메이션을 추가할 수 있다.

DiffUtil

원래 리스트와 새로 들어온 리스트 간의 차이를 계산하고 DiffUtil.Callback 이라는 추상 클래스를 콜백 클래스로 활용하게 된다.

  1. calculateDiff() 에서 diff 알고리즘을 통해 변경된 아이템을 감지한다.
  2. dispatcUpdatesTo()에서 지정된 Adapter로 업데이트 이벤트를 전달한다.
public void dispatchUpdatesTo(@NonNull RecyclerView.Adapter adapter){
		List oldList = mAdapter.getData();
    DiffResult result = DiffUtil.calculateDiff(new MyCallback(oldList, newList));
    mAdapter.setData(newList);
    result.dispatchUpdatesTo(mAdapter);
}

DiffUtil.Callback 클래스를 구현하려면 총 네 가지의 메서드를 오버라이딩 해야 한다.

override fun getOldListSize(): Int {
	TODO("Not yet implemented")
}

override fun getNewListSize(): Int {
	TODO("Not yet implemented")
}

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
	TODO("Not yet implemented")
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
	TODO("Not yet implemented")
}


AsyncListDiffer

https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer

https://hungseong.tistory.com/24

DiffUtil의 경우 리스트의 아이템이 많으면 하나하나 모두 비교 연산을 수행하므로 작업 시간이 길어질 수 있다. 이를 위해 비교 연산을 백그라운드 스레드에서 처리하고자 한다.

public AsyncListDiffer(@NonNull RecyclerView.Adapter adapter,
        @NonNull DiffUtil.ItemCallback<T> diffCallback) {
    this(new AdapterListUpdateCallback(adapter),
        new AsyncDifferConfig.Builder<>(diffCallback).build());
}

Adapter와 DiffUtil을 인자로 받아 DiffUtil을 백그라운드 스레드에서 수행하고 리사이클러뷰에 결과를 반영 할 수 있게 한다.

class ItemOrderUIModelDiff : DiffUtil.ItemCallback<ItemOrderUIModel>() {
    override fun areItemsTheSame(oldItem: ItemOrderUIModel, newItem: ItemOrderUIModel): Boolean {
        return oldItem.id == newItem.id
    }

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

}

areItemsTheSame()을 먼저 수행하고 true일 때만 areContentsTheSame()을 수행한다.

적용