Android Recyclerview StableIDs when Replacing Entire List - android

According to Android documentation:
Enabling Stable IDs will make the recyclerview do less work when
updating the list. Even if we call the notifyDataSetChanged(), it does
not have to handle the complete re-ordering of the whole adapter
because it can find if the item at a position is the same as before,
which results in faster performance of the recyclerview.
It also states that I should prefer notifyOnItemChanged(), notifyOnItemRemoved(), notifyOnItemInseted() etc. instead of notifyDataSetChanged() and prompts me to use it as last resort.
However, what happens if I simply want a recyclerview that doesn't support operations such as add/remove/replace at position and It is designed to replace the entire list at once? For example, I might want to display either Popular or Top Rated movies, which means that the entire content in the recyclerview will be changed. In this case, is it faster to simply:
setHasStableIDs(False);
notifyDataSetChanged();

Related

how to update the data in specific position in the recyclerview without notifying the whole item? (Ex. text, image etc)

I need the functionality to update the data in the item in the recycler view. right now, If we notify the whole item it shows some fluctuation and we want to avoid refreshing the whole item on the UI.
I am using the ListAdapter with diff utils.
There are many ways to achieve your goal.
self-managing items. Adapter doesn't know anything about content of the items, it only puts items into RecyclerView. Content is managed by the item itself, so your problem is already solved.
custom adapter. Adapter has intricate knowledge about every item and can update selected ones accordingly.
AsyncListDiffer You can add differ to your adapter and it will take care of not updating parts that need no update.
Without seeing your code, we can't tell which way would be the most appropriate for you, but I guess adding differ is the simplest on already working code.
You need to create custom Adapter:
https://developer.android.com/develop/ui/views/layout/recyclerview
If you're talking about updating specific list items, and you're not using a DiffUtil (which will handle it for you) then you need to call the appropriate notify* method on your Adapter.
They fall into two categories, item change events (where the item list stays the same, but the displayed data for one or more of those items changes) and structural change events (where the actual list of items changes in some way, e.g. insertion/removal, or reordering).
I'm assuming you just want to update the displayed data for an item, so you should use one of the notifyItemChanged or notifyItemRangeChanged methods to inform the adapter that a certain item (or range of items) needs to update. If any of those items are currently being displayed in a ViewHolder, then onBindViewHolder will get called again for those items - which is where you set all your text, images etc depending on the item you're displaying. So you'll update them with the current data.
Both those methods have a version that takes a payload Object/Any, where you can pass in some data to be used in a partial bind - basically, onBindViewHolder can receive that data and be smarter about the update, which means you can avoid things like reloading images, etc. by passing in some stuff and checking for it during the binding process. More info about that here in the other version of onBindViewHolder you can implement, if you need to.

DiffUtils vs stable Ids in recycler view

I have been reading a lot about the optimisations in RecyclerView
for quite some time and have learnt a lot of new concepts. One thing that isn't still clear is that can we use both stable ids and DiffUtils together in a RecyclerView. Are there possible benefits/drawbacks of this approach? From what I have read, I think using DiffUtils alone will give all the possible benefits of the reuse of viewHolders and nice animations(correct me if I am wrong). A detailed comparison would be really helpful.
Long story short, DiffUtill fully replaces stableIds approach.
StableIds is a legacy approach from the times when everybody was migrating from ListView to RecyclerView. Along with ItemAnimator it provided an easy approach to get simple predictive animations out of the box. Predictive meaning that RV could deduce itself which items are added/removed or moved when you just called notifyDataSetChanges without bothering about other callbacks.
Once DiffUtil came along there were no need to RV to deduce that, cause DiffUtills tells RV exactly which items are being moved/added/removed.
I use RV in very tough conditions with dozens of item types, and multiple data updates per second, and spend dozen hours debugging RV and animations internals and didn't notice any significant changes in its scrapping/de-scrapping/1-2-3-steps-layouting behaviour when was trying to add stableIds on top of DiffUtil.
Here's a big piece on how animations worked in circa 2015 pre DiffUtill:
https://www.birbit.com/recyclerview-animations-part-1-how-animations-work/
https://www.birbit.com/recyclerview-animations-part-2-behind-the-scenes/
And a little bit more if you're interested in RV internals:
https://android.jlelse.eu/anatomy-of-recyclerview-part-1-a-search-for-a-viewholder-404ba3453714
Yes, you can.
If you use androidx.recyclerview.widget.ListAdapter (which you should), you actualy has to provide a DiffUtil. Just look at the constructor. And then nothing is stopping you from providing stable ids.
Actualy, if you don't use stable ids, and submit a new list with event just a minor change, all the items in RecyclerView will "flash". But if you use stable ids, the change will animate nicely.
Also know, that they have no dependency on each other, you'll just probably use the same id (or whatever) field from your items in both getItemId() and DiffUtil.
As per docs DiffUtils:
DiffUtil is a utility class that can calculate the difference between
two lists and output a list of update operations that converts the
first list into the second one.
It can be used to calculate updates for a RecyclerView Adapter. See
ListAdapter and AsyncListDiffer which can compute diffs using DiffUtil
on a background thread.
DiffUtil uses Eugene W. Myers's difference algorithm to calculate the
minimal number of updates to convert one list into another. Myers's
algorithm does not handle items that are moved so DiffUtil runs a
second pass on the result to detect items that were moved.
and as per this Answer StableIds is
Stable IDs allow the ListView to optimize for the case when items remain the same between notifyDataSetChanged calls. The IDs it refers to are the ones returned from getItemId.
Without it, the ListView has to recreate all Views since it can't know if the item IDs are the same between data changes (e.g. if the ID is just the index in the data, it has to recreate everything). With it, it can refrain from recreating Views that kept their item IDs.
Hope you concept will clear now.

when does notifydatasetchanged animates list items separately?

I know that notifydatasetchanged updates the whole list and it is recommended to use DiffUtil to only update changed items, what I am not understanding yet after a lot of research is if it's expected that notifydatasetchanged animates list items separately when being used in a RecyclerView. Because I have one RecyclerAdapter where I replace the dataset completely and then call notifyDataSetChanged leading to list items being animated perfectly, only those added get the default added animation, removed ones get the removed animation and so on. At the same time I have another adapter where I also do the same, call notifyDataSetChanged but here the whole list flashes shortly, I am not getting any animations automatically, so I don't know from what does notifydatasetchanged make this dependent? Both adapters are too complex and long to post here.
I found the answer here:
The framework will attempt to animate views if your adapter uses
stable IDs, which provides enough data to guess which views are
removed/added/etc

Prevent RecyclerView to change position when loading additional items

I have a RecyclerView with setStackFromEnd(true) representing a chat list. And I want to load older messages when the list is scrolled to the top. I managed to do this using onScrollListener.
But when I add items to the adapter with messages.addAll(0, aListWithNewMessages) (messages is data set for adapter) and call notifyDataSetChanged(), new list items (as expected) appear before the existing ones and shift them down (not the experience a user wants), and I want to add them silently so a user shouldn't see it.
So my guess for how to tackle this issue is to scroll list to somehow previously saved position.
I understand that this is not a bug or an unexpected behavior, so please help to sort it out.
Thanks
Try being more specific. Instead of calling notifyDataSetChanged() use notifyItemRangeInserted or similar RecyclerView methods. That will allow RecyclerView to know what to do and will provide much better UX.

Is there a way to call BaseAdapter.notifyDataSetChanged() on a single object?

Is there a way to call BaseAdapter.notifyDataSetChanged() on a single element in the adapter.
What I am trying to do is update the data and reflect those changes in the containing ListView. The problem is that sometimes the change is so small that it seems ridiculous that I have to refresh the whole view rather than the single item in the view that has been updated.
I am not aware of such method. If it's really important, you can always find individual item view to update. But I don't think that it worth it as Android is pretty efficient in updating list views. So it will not do much extra work (definitelly not going beyond items currently visible on the screen).

Categories

Resources