안드로이드에서 RecyclerView에 표시하는 데이터에 변화가 생긴경우 보통 Adapter클래스의 notifyDataSetChanged() 메서드를 사용해 일괄 업데이트하는 방식으로 만들게 된다. 변경된 데이터만 업데이트 하거나 일정 범위만 업데이트하는 방법도 있지만, 작동이 생각한대로 안될때가 많아서 맘편하게 notifyDataSetChanged()로 일괄 업데이트한다.
이 경우 RecyclerView에 전체 데이터를 업데이트해서 새로 표시하기 때문에 데이터개수가 많아질수록 성능이 저하되는 문제가 생겨 DiffUtil이 등장하게되었고, DiffUtil사용시 변경된 데이터에 대해서만 RecyclerView를 업데이트하면서 기본적인 삭제,추가에 대한 애니메이션도 볼 수 있다.
class MyDiffUtil(
private val oldItems: List<Item>,
private val newItems: List<Item>
): DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItems[oldItemPosition].id == newItems[newItemPosition].id
}
override fun getOldListSize(): Int {
return oldItems.size
}
override fun getNewListSize(): Int {
return newItems.size
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItems[oldItemPosition] == newItems[newItemPosition]
}
}
DiffUtil.Callback()를 상속한 클래스를 작성하고 필수 메서드 4개를 오버라이드한다.
데이터 비교를 위해 두개의 List 변수를 선언하고 생성자를 통해 넘겨받을수 있도록 한다.
getOldListSize, getNewListSize 두개의 메서드는 이름에 맞춰서 List의 Size를 넘겨주도록 작성한다.
areItemsTheSame() : Item의 고유한 Id를 비교하도록하는 메서드이다. 고유 Id는 Model Class 작성시 만든 Id나 Id가없으면 List의 Position정도로 대체할 수 있다.
areContentsTheSame() : Id가 아닌 실제 Contents를 비교하는 메서드이다. areItemsTheSame()가 true를 반환할 경우 areContentsTheSame()가 실행되고 여기서 false를 반환하면 Update하는 방식. Java로 작성할경우 좀 더 상세한 정의가 필요하다. 위의 코드는 Kotlin data class이기 때문에 == 연산만으로 비교가 가능.
Adapter 클래스에 RecyclereView를 업데이트할 수 있도록 메서드 추가
fun setItem(items: List<Item>) {
val result = DiffUtil.calculateDiff(ParcelDiffUtil(mItems, items))
mItems.clear()
mItems.addAll(items)
result.dispatchUpdatesTo(this)
}
mItems : Adpater에서 사용하는 List 객체
items : ViewModel같은 컨트롤러에서 만들어서 넘기는 List객체