RecyclerView — More Animations with Less Code using Support Library ListAdapter
ListAdapter
is a new class bundled in the 27.1.0 support library and simplifies the code required to work with RecyclerViews
. The end result is less code for you to write and more recycler view animations happening for free.
Why is it great? It’s great because it automatically stores the previous list of items and utilises DiffUtil
under the hood to only update items in the recycler view which have changed. This typically means better performance as you avoid refreshing the whole list, and nicer animations because only items which change need to be redrawn.
🎉 Since the new ListAdapter
is built on top of DiffUtil
it leverages it for you, meaning you have less callbacks to implement to achieve recycler view animations.
Let’s say you have this class which represents a user’s tasks in a todo app. This example happens to be a Room entity but that’s not required.
Adapter — The Old Way
To display a list of tasks in a recycler view, previously you would have written your adapter to inherit from RecyclerView.Adapter<ViewHolder>
and it might have looked something like this.
The biggest problem this code has is that it only handles adding new tasks and wouldn’t cope with deletions or edits. If we wanted to easily handle those cases as well, we could cheat and use notifyDataSetChanged()
but we’d lose the nice animations. To handle them properly, we’d need to implementDiffUtil
which is a bit more work.
DiffUtil
If you use ListAdapter
you won’t have to fully implement DiffUtil
, but it’s still useful to know what problem is being solved for you.
ListAdapter
is built on top of DiffUtil
meaning it handles some of the diffing logic for you. If you aren’t familiar with DiffUtil
, it was created to further encourage developers to let the RecyclerView
only update the contents which changed; resulting in better performance when items are inserted, updated or deleted.
If you are still using notifyDataSetChanged()
then you are forcing the entire list to be redrawn and therefore not allowing Android the chance to show nice visual cues to the user as to what exactly just changed. Instead of reloading the entire list, you can use methods like notifyItemInserted
, notifyItemChanged
and notifyItemRemoved
. These result in lovely animations but working out which method to invoke manually is non-trivial.
DiffUtil
helps you by calculating which methods to invoke out of inserted/changed/removed
.
DiffUtil
is great but it still requires a bit of boilerplate to implement.
Adapter — The New Way
To make use of the new ListAdapter
we would update the existing adapter so that it inherits ListAdapter
and pass in the type of item it will show — Task
in this case — as well as the ViewHolder
.
We no longer need to hold onto a reference of our item list as ListAdapter
does this for you. Whenever you need your item list, you can call getItem(int).
DiffUtil.ItemCallback
In the constructor, you need to provide a DiffUtil.ItemCallback
which is a slimmed down version of the DiffUtil
callbacks.
DiffUtil.ItemCallback
requires you to implement two functions: areItemsTheSame
and areContentsTheSame
areItemsTheSame
areItemsTheSame
hands you two items and asks you if they fundamentally represent the same object. In my case, I have a unique ID I can use to compare. If the IDs match, then I know the items are the same even if some of their other fields may differ.
areContentsTheSame
areContentsTheSame
hands you two items again. This time, though, it asks you if the two items have the same content. If you decide your items do have the same content, then no redraw and no animation are required; you are already displaying the object and you are saying that nothing has changed.
However, if you decide the contents are not the same, then the item will be redrawn on screen.
Shiny New Adapter
It’s not much different from the old adapter. We have a new superclass, we’ve deleted the list of items we were storing previously and we’ve ditched the manual addTask
method we had before. In the constructor, we pass in an instance of our DiffUtil.ItemCallback
.
Updating the Adapter
Whenever you need to update the adapter, you can provide the new list of items to it using the submitList(List)
method.
You aren’t tied into using Room
or LiveData
and so long as you can obtain an updated list, you can make use of ListAdapter
.
But it sure is nice when you do use Room
and LiveData
😎. Whenever you are notified of a change, just submit that straight to the adapter and it’ll take care of the rest.
Summary
RecyclerView is great. But it’s better when animations are shown as its contents are changed. You can cheat and update the entire list every time something changes but that’s usually not necessary. You can achieve better performance and those nice animations yourself with a bit of code.
Or you can make use of ListAdapter
. The end result is less code, more animations and happier users 😃.