Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView crashes when updating on top

I have a RecyclerView in my app everything is working fine I am while scrolling when the last item is visible I am adding some more item to the bottom and it is working fine. Now what the problem is that I have a Handler which runs after every 5 seconds and check if there is any update in the web service and if there is any update i just load the data to the top of the RecyclerView it works fine when I have not scrolled the RecyclerView but when i scroll it and the Handler is called(as it is called after every 5 seconds) then while updating the RecyclerView on the top the app crashes.

Updating function at the top:

public void addOnTop(ArrayList<ItemPOJO> topItemList) {
    for (int i = topItemList.size() - 1; i >= 0; i--) {
        itemList.add(0, topItemList.get(i));
    }
    notifyItemRangeInserted(0, topItemList.size());
    notifyDataSetChanged();
}

This is the Error log:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{419b8760 position=5 id=-1, oldPos=-1, pLpos:-1 no parent}
        at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4214)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4345)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4326)
        at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1955)
        at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1364)
        at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1327)
        at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1155)
        at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1012)
        at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1363)
        at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2227)
        at android.view.View.dispatchTouchEvent(View.java:7190)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2274)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2009)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2280)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2023)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1931)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1385)
        at android.app.Activity.dispatchTouchEvent(Activity.java:2396)
        at android.support.v7.internal.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:59)
        at android.support.v7.internal.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:59)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1879)
        at android.view.View.dispatchPointerEvent(View.java:7370)
        at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3182)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3127)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4164)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4143)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4235)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
        at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
        at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
        at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4214)
        at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4254)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
        at android.view.Choreographer.doCallbacks(Choreographer.java:555)
        at android.view.Choreographer.doFrame(Choreographer.java:523)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreog

P.S.: com.android.support:recyclerview-v7:22.2.1 is used

like image 528
Vishwajit Palankar Avatar asked Jul 24 '15 06:07

Vishwajit Palankar


4 Answers

This crash might be caused by the fact that the setViewHolder and onBind methods are being called while your list(used by the adapter) is being updated, but notifyDataSetChanged() hasn't been called. This usually happens if you scroll through the list, or fling, while the list is being updated.

Solution: Maintain a separate list(tempList) of ItemPOJOs and append the topData in that list. Then clear the list used for the adapter, set the list of the adapter with the tempList, and call notifyDataSetChanged().

like image 108
Sid Avatar answered Nov 01 '22 04:11

Sid


It is a bug of RV, see the discussion here.
In most cases, use notifyDataSetChanged() will avoid this crash, but it will kill Animation and Performance.

like image 24
Piasy Avatar answered Nov 01 '22 04:11

Piasy


Change your code like this:

public void addOnTop(ArrayList<ItemPOJO> topItemList) {
    Collections.reverse(topItemList);
    itemList.addAll(0, topItemList);
    notifyItemRangeInserted(0, topItemList.size());
}

it's weird but in this way I resolved my problem!

like image 34
MaryPeak Avatar answered Nov 01 '22 04:11

MaryPeak


Try disabling recyclerview while refreshing:

recyclerView.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
          return true;
      }
  });
like image 42
Rishabh Srivastava Avatar answered Nov 01 '22 05:11

Rishabh Srivastava