Android RecyclerView DiffUtil — Complete Guide
In this tutorial, you'll learn about Android RecyclerView DiffUtil. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
Your DiffUtil makes items jump around, animations look wrong, or the diff computation blocks the UI thread on large lists.
Wrong Approach ❌
// Diff computed synchronously on the main thread
val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(i: Int, j: Int) = oldList[i].id == newList[j].id
override fun areContentsTheSame(i: Int, j: Int) = oldList[i] == newList[j] // Object reference check!
})
result.dispatchUpdatesTo(adapter)
Output: Items always appear as "changed" because object equality fails.
Right Approach ✅
class UserDiffCallback(
private val oldList: List<User>,
private val newList: List<User>
) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
return oldList[oldPos].id == newList[newPos].id
}
override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean {
return oldList[oldPos].name == newList[newPos].name &&
oldList[oldPos].avatarUrl == newList[newPos].avatarUrl
}
}
// Use AsyncListDiffer for background computation
val differ = AsyncListDiffer(this, object : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(a: User, b: User) = a.id == b.id
override fun areContentsTheSame(a: User, b: User) = a.name == b.name
})
differ.submitList(newList)
Output: Correct item animations with background diff computation.
Prevention
- Always use
AsyncListDifferorListAdapterfor background diffing. - Compare individual fields in
areContentsTheSame, not object references. - Return
falsefromareContentsTheSameand usegetChangePayload()for partial bind updates. - Never call
dispatchUpdatesToon the main thread for lists > 100 items.
Common Mistakes with recyclerview diffutil
- Mixing let bindings with <- bindings in do notation, producing type errors
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro