i am porting my adapter into RecyclerView.Adapter
what i want to achieve: when the user scrolls down near the end i want to start fetch data, i also want to add i ProgressBar view at the end to let the user know more data is coming.
the way i implemented this in my BaseAdapter: on getView
in the view requested in near the end, i would start fetching more data, call notifyDataSetChanged (to get the ProgressBar view to show) and only then return the view needed forgetView
.
what i tried doing in RecyclerView.Adapter: i tried to do the same thing basically, this time in the method onBindViewHolder
,
but if i try and call notifyItemInserted
inside this method i get the following exception:
IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
what i tried: i noticed that onBindViewHolder
gets called from onLayoutChildren
from LayoutManager
, i tried overriding it and calling notifyItemInserted
after its super
but i got the same exception
how can i achieve my goal?
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
};
handler.post(r);
My sample code where I call adapter.notifyDataSetChanged(); from Activity
It's also worth noting the JavaDoc on the RecyclerView.isComputingLayout()
method that triggers this exception :
/**
* Returns whether RecyclerView is currently computing a layout.
* <p>
* If this method returns true, it means that RecyclerView is in a lockdown state and any
* attempt to update adapter contents will result in an exception because adapter contents
* cannot be changed while RecyclerView is trying to compute the layout.
* <p>
* It is very unlikely that your code will be running during this state as it is
* called by the framework when a layout traversal happens or RecyclerView starts to scroll
* in response to system events (touch, accessibility etc).
* <p>
* This case may happen if you have some custom logic to change adapter contents in
* response to a View callback (e.g. focus change callback) which might be triggered during a
* layout calculation. In these cases, you should just postpone the change using a Handler or a
* similar mechanism.
*
* @return <code>true</code> if RecyclerView is currently computing a layout, <code>false</code>
* otherwise
*/
public boolean isComputingLayout() {
return mLayoutOrScrollCounter > 0;
}
The salient phrase being :
In these cases, you should just postpone the change using a Handler or a similar mechanism.
In my case, I was modifying the adapter contents from another thread, which was (occasionally) causing a collision. Shifting the update to a Handler on the UI thread naturally solves this.
Using a Handler
for adding items and calling notify...()
from this Handler
fixed the issue for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With