Ответ
DiffUtil использует два Callback'а (DiffUtil.Callback и DiffUtil.ItemCallback) для разделения логики сравнения элементов и их идентификации.
DiffUtil.Callback (для RecyclerView.Adapter):
- Сравнивает старый и новый списки целиком
- Используется в
ListAdapter/AsyncListDiffer - Требует реализации
getOldListSize(),getNewListSize(),areItemsTheSame(),areContentsTheSame()
ItemCallback (для AsyncListDiffer):
- Оптимизирован для пошагового сравнения
- Упрощает работу с
Pagingи асинхронными обновлениями
Пример ItemCallback:
val diffCallback = object : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(old: User, new: User) = old.id == new.id
override fun areContentsTheSame(old: User, new: User) = old == new
} Ответ 18+ 🔞
Эй, слушай, тут про эту вашу DiffUtil штуку. Ну, понимаешь, чтобы в RecyclerView всё красиво обновлялось, а не просто notifyDataSetChanged(), от которого всё дергается, как будто в телевизоре помехи.
Так вот, у этой штуки есть два главных коллбэка, как два брата-близнеца, но один — бухгалтер, а второй — каскадёр. DiffUtil.Callback — это тот самый бухгалтер, дотошный такой. Он садится и сравнивает два списка — старый и новый — от начала до конца, каждый элемент. Ему надо всё знать: сколько было, сколько стало (getOldListSize, getNewListSize), это один и тот же предмет или нет (areItemsTheSame), и если да, то не поменялось ли в нём чего (areContentsTheSame). Честно, иногда от этой бюрократии терпения ноль, ебать. Но без него никуда, особенно в обычном RecyclerView.Adapter.
А вот ItemCallback — это уже каскадёр, оптимизированный под движуху. Он не смотрит на весь список сразу, а может сравнивать элементы по одному, что для асинхронных штук, типа того же Paging библиотеки — просто песня. Он проще и используется внутри AsyncListDiffer или ListAdapter. По сути, это тот же самый принцип, но упакованный по-современному.
Вот смотри, как это выглядит на практике, чтобы не быть голословным. Берёшь и пишешь:
val diffCallback = object : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(old: User, new: User) = old.id == new.id
override fun areContentsTheSame(old: User, new: User) = old == new
}
Всё, бля! В первой строчке говоришь: «Чувак, если айдишники совпали — это один и тот же юзер, даже если он теперь блондин». Во второй: «А если и все остальные поля одинаковые, то вообще овердохуища, и перерисовывать нечего». Красота!
Главное — не перепутать, где какого брата использовать, а то будет тебе хиросима в списке вместо плавных анимаций.