Is it okay to do the RecyclerView setAdapter() several times? - android

When use RecyclerView, Does it matter how many times setAdapter() has been used?
Or should setAdapter be used only once?
and Is it okay to use setAdapter after adding items to the adpater?
Or should the setAdapter work before adding items to the adapter?

General practise is to call RecyclerView::setAdapter once per instantiation of the RecyclerView then use the RecyclerView.Adapter<VH> for updating the underlying List<T> data set then calling methods like Adapter::notifyDatasetChanged.
Recyclerview.Adapter also allows updating individual rows through other methods : https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.Adapter
More modern techniques include DiffUtil or AsyncListDiffer which uses DiffUtil or manual implementations to abstract working out individual row changes between data set updates. This is the most efficient mechanism as it only needs to "rebind" changed data on screen, rather than rebinding all views.
If you intend to change the type T of the underlying data set then you can call RecyclerView::setAdapter more than once, as you are fundamentally changing the adapter data set type. This however is an edge case.

Unless you are switching different adapters on the same RecyclerView, it's recommended you call setAdapter once (even with an empty list of elements). Then, when you update the list of elements, you can call adapter methods like notifyDataSetChanged and other similar methods.

Well, if you are setting the same adapter instance multiple times just to refresh then, please take a look at RecyclerView.Adapter#notifyDataSetChanged()
A better approach would be 'setAdapter work before adding items to the adapter' and then you can add, remove, and modify adapter data items. Then you can notify the adapter.

Related

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

notifyDataSetChanged vs notifyItemInserted

I'm confused if we use the two methods to tell the adapter that data you point were changed so what is the difference between them.
notifyDataSetChanged() can be thought of as a "major" change. You're telling the adapter that everything in the data set has changed, and so it should re-bind every single child.
notifyItemInserted() (and the other methods like notifyItemRemoved() etc) can all be thought of as "minor" changes. You're telling the adapter exactly how the data set has changed, and so it can perform optimizations (like only re-binding the affected children).
Notably, using the "minor" change methods will also give you nice animations by default, which makes it a lot easier for the user to see what changed in the list.
Based on the documentation
notifyDataSetChanged():
This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.
notifyItemInserted()
Representations of other existing items in the data set are still considered up to date and will not be rebound, though their positions may be altered.
Main difference is that notifyDataSetChanged() will cause more overhead since it will force LayouManagers to full rebind the views where as notifyItemInserted() will not rebound all the views again but rather alter positions for them.
For better performance, rely on notifyDataSetChanged() as a last resort. Use the more specific change events (like notifyItemInserted()) wherever possible for better efficiency.
notifyItemInserted(int position) takes the position of your inserted item as an argument, notifies about that item insert and thus also shifts positions after that item.
notifyDataSetChanged() notifies that the data set connected to the adapter has changed.

What's better? notifyDataSetChanged or notifyItemChanged in loop?

So I have an activity with RecyclerView and I want to change TextView of every item in the RecyclerView by pressing button that has onClickListener() in the activity.
I'm wondering what is better in terms of performance:
Use notifyDataSetChanged ones.
Use loop with condition like int i is less than List.size() where notifyItemChanged would be called few times.
In both cases I create boolean variable in RecyclerView Adapter which is used by onBindViewHolder to know how to update item. By default it's false and after button click it becomes true so onBindViewHolder updates item in different way.
Also I would like to know if this approach is suitable at all.
If you are simply updating one part of the view, use the notifyItemRangeChanged()or notifyItemChanged() instead of notifiyDataSetChanged(). The difference here has to do with structural changes vs item changes. This is on the android developers RecyclerView.Adapter documentation found here.
Here is another tidbit on the differences between the two types of changes:
There are two different classes of data change events, item changes
and structural changes. Item changes are when a single item has its
data updated but no positional changes have occurred. Structural
changes are when items are inserted, removed or moved within the data
set.
This is taken from that aforementioned page,
If you are writing an adapter it will always be more efficient to use
the more specific change events if you can. Rely on
notifyDataSetChanged() as a last resort.
So just to clarify use notifyDataSetChanged() as a last resort, and instead ask yourself if you can preform one of these methods instead, and if you can use it instead:
notifyItemChanged(int)
notifyItemInserted(int)
notifyItemRemoved(int)
notifyItemRangeChanged(int, int)
notifyItemRangeInserted(int, int)
notifyItemRangeRemoved(int, int)
which makes sense because notifyDataSetChanged() will pretty much try to redraw everything based on the data and make no previous assumptions on it, while the other methods will just look for changes. That means the adapter has to do a lot more work that is not necessary. This is what notifyDataSetChanged() does:
This event does not specify what about the data set has changed,
forcing any observers to assume that all existing items and structure
may no longer be valid. LayoutManagers will be forced to fully rebind
and relayout all visible views.
This also makes sense to use the incremental or range approach, because you are changing the text, you need to go get each new text and when you do that you should tell the adapter you changed it. Now, if you do a button click and get all new text values, and create a new list or something then call heavy notifyDataSetChanged().
I would definitely call notifyDataSetChanged() if all of the data items ar no longer valid. When you call notifyItemChanged(mPos), it is equivalent to a call to notifyItemRangeChanged(mPos, 1), and every time it is called, requestLayout() is also called. On the other hand, when you call notifyDataSetChanged() or notifyItemRangeChanged(0, mList.size()), there is only one call to requestLayout().
Your question should now be, what is better, a call to notifyDataSetChanged() or notifyItemRangeChanged(0, mList.size())? For that one I don't have an answer.
I've noticed that notifyItemChanged(mPos) triggers onBindVieHolder for corresponding position even it's currently not visible.
For me, calling it in a loop for all elements was more costly than notifyDatasetChanged which redrawn only visible ones.
So be careful with large datasets.

Is there any negative effects in calling the notifyDataSetChanged consecutive/several times (user-triggered)?

I am extending the ArrayAdapter and I provided my own OnItemClickListener where I update certain states of my data which reflects on multiple items in the list so to update the current states of those items in the list, I am calling the notifyDataSetChanged. Its working properly as how I want it to my worry is if there are any issues or negative effects on doing so. Like when the user taps many items which results in consecutive calls to notifyDataSetChanged.
If the user interaction requires views to be updated then you do need to be calling notifyDataSetChanged each time. If you're really worried you can look at debounce algorithms but that's kind of overkill, but as long as you don't have a huge number of elements and don't add a bunch of data change listeners it shouldn't be a problem.
don't worried about calling notifyDataSetChanged it only notify adapter about data change

How to force my GridView adapter to reload?

I'm an Android beginner starting with fragments. My problem is the following.
I has a fragment that used to show a custom listview (it extended SherlockListFragment). I populated the listview with some data server. The action of retrieveing data of the server was executed in another thread and I had a handler to manage responses. In this handler (inside my fragment) I recovered data for my adapter and the I reloaded my adapter like this ((myAdapter) fragment.getListAdapter()).dataChange(); .
Well, now I wanted to convert the list in a custom grid cause I think it's much better for my app. So, the fragment doesn't extends SherlockListFragment, but BaseFragment. As I don't have a ListView anymore, I can't not use "getListAdapter.datachange()". Does anybody know the correct way to do this?
Thanks in advance.
Make an Adapter for the gridview that extends from BaseAdapter, or use an Adapter that extends from BaseAdapter.
then call notifyDataSetChanged on that adapter when the contents of your collection has changed.
Small example of adapter and grid
I would recommend making your changes on the Adapter, not the Grid (or list). Depending on the type of adapter you are using there are a couple different approaches.
ArrayAdapter
For an ArrayAdapter, using the standard modification methods (add, addAll, clear, remove) should update any views.
CursorAdapter
A CursorAdapter works in much the same way, except that you use either swapCursor or changeCursor to change the underlying data. That should notify all data set observers that the underlying data has changed.
All Adapters
If your observers don't get notified, usually because setNotifyOnChange was called, you can call mAdapter.notifyDataSetChanged() to manually update all listeners (UI views, services, etc.) that the underlying data has changed.
thanks a lot for your quick responses. I tried your ideas but finally I converted my old list in a grid by making a two columns' row. It was the best option to keep my header and footer on.

Categories

Resources