ListAdapter
ListAdapter는 RecyclerView.Adapter를 베이스로 한 클래스로 RecyclerView의 리스트 데이터를 표현해주며 리스트를 백그라운드 스레드에서 diff(차이)를 처리하는 특징이 있습니다.
리스트 데이터를 갱신하기 위해서 notifyDataSetChanged()를 호출하는 경우를 볼 수 있습니다.
그러나 수많은 데이터 중 갱신될 데이터가 하나뿐이더라도 모든 항목을 통째로 갱신하게 됩니다.
이러한 불필요한 교체 비용을 줄이기 위해 고안된 것이 바로 DiffUtil입니다.
DiffUtil
DiffUtil은 RecyclerView의 성능을 한층 더 개선할 수 있게 해주는 유틸리티 클래스입니다.
기존의 데이터 리스트와 교체할 데이터 리스트를 비교해서 실질적으로 갱신이 필요한 아이템들을 추려냅니다.
DiffUtil을 사용하기 위해서 두 리스트의 차이를 계산해주는 DiffUtil.Callback()을 구현해야 합니다.
- areItemsTheSame() : 두 아이템이 동일한 아이템인지 체크합니다. 예를 들어, item이 자신만의 고유한 id를 가지고 있다면 그것을 기준으로 삼으면 됩니다.
- areContentsTheSame() : 두 아이템이 동일한 내용물을 가지고 있는지 체크합다. 이 메서드는 areItemsTheSame()가 true일 때만 호출됩니다.
class BaseDiffUtil<T>(
private val newList: List<T>,
private val oldList: List<T>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
newList[newItemPosition].id == oldList[oldItemPosition].id
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
newList[newItemPosition] == oldList[oldItemPosition]
}
DiffUtil.calculateDiff(diffUtil)로 업데이트가 필요한 리스트를 찾을 수 있습니다. 아이템 개수가 많을 경우에는 비교 연산 시간이 길어지므로 calculateDiff는 백그라운드 스레드에서 처리되어야 합니다.
notifyDataSetChanged() 대신 dispatchUpdatesTo(Adapter adapter)를 사용하면 교체가 필요한 아이템에 대해서 부분적으로 데이터를 교체하라는 notify가 실행됩니다.
val items = mutableListOf<T>()
fun setItems(newItems: List<T>) {
val diffUtil = BaseDiffUtil(items, newItems)
val diffResult = DiffUtil.calculateDiff(diffUtil)
items.clear()
items.addAll(newItems)
diffResult.dispatchUpdatesTo(this)
}
AsyncListDiffer
DiffUtil을 더 단순하게 사용할 수 있게 해주는 클래스이며, 자체적으로 멀티 쓰레드에 대한 처리가 되어있기 때문에 개발자가 직접 동기화 처리를 할 필요가 없습니다.
AsyncListDiffer을 사용하기 위해서 아이템을 비교해주는 DiffUtil.ItemCallback()을 구현해야 합니다.
또한, Adapter 내부에서 AsyncListDiffer 객체를 사용할 수 있습니다.
- getCurrentList() : 현재 리스트 반환
- submitList(List<T> newList) : 리스트 데이터 교체
- onCurrentListChanged() : 리스트가 업데이트 되었을 때 실행할 콜백 지정
class ImageAdapter() : ListAdapter<ImageItems, RecyclerView.ViewHolder>(
object : DiffUtil.ItemCallback<ImageItems>() {
override fun areItemsTheSame(oldItem: ImageItems, newItem: ImageItems): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: ImageItems, newItem: ImageItems): Boolean {
return oldItem == newItem
}
}
) {
// ...
}
// 외부에서 실행
val imageAdapter = ImageAdapter()
imageAdapter.submitList(newItems) // 아이템 업데이트
val imageList = imageAdapter.currentList // 현재 리스트 반환
'안드로이드 > 활용' 카테고리의 다른 글
[Android] MediaPlayer와 MediaRecoder (0) | 2023.08.02 |
---|---|
[Android] ViewPager2 사용하기 (0) | 2023.07.31 |
[Android] RecyclerView (0) | 2023.07.26 |
[Android] addView와 ListView (0) | 2023.07.25 |
[Android] Room 사용하기 (0) | 2023.07.24 |