Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView notifyItemInserted IllegalStateException

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?

like image 695
user1333057 Avatar asked Oct 24 '14 20:10

user1333057


3 Answers

        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

like image 101
Rafael Avatar answered Oct 25 '22 21:10

Rafael


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.

like image 22
Kas Hunt Avatar answered Oct 25 '22 21:10

Kas Hunt


Using a Handler for adding items and calling notify...() from this Handler fixed the issue for me.

like image 9
cybergen Avatar answered Oct 25 '22 22:10

cybergen