Everyone present (station), must have encountered such a bug in the use of RecyclerView, and see the log.

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{2064e5c6 position=2 id=-1, oldPos=2, pLpos:-1 scrap [attachedScrap] tmpDetached no parent} at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4505) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(Recycl erView.java:4636) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(Recycl erView.java:4617) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayo utManager.java:1994) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutMa nager.java:1390) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java :1353) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayo utManager.java:574) at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.ja va:2979) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2904) at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3283) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1959) at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1948) at android.widget.LinearLayout.onLayout(LinearLayout.java:1724) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1959) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1813) at android.widget.LinearLayout.onLayout(LinearLayout.java:1722) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:633) at  android.widget.FrameLayout.onLayout(FrameLayout.java:568) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1959) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1813) at android.widget.LinearLayout.onLayout(LinearLayout.java:1722) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:633) at  android.widget.FrameLayout.onLayout(FrameLayout.java:568) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:633) at  android.widget.FrameLayout.onLayout(FrameLayout.java:568) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1959) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1813) at android.widget.LinearLayout.onLayout(LinearLayout.java:1722) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:633) at  android.widget.FrameLayout.onLayout(FrameLayout.java:568) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:633) at  android.widget.FrameLayout.onLayout(FrameLayout.java:568) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:633) at  android.widget.FrameLayout.onLayout(FrameLayout.java:568) at android.view.View.layout(View.java:15912) at android.view.ViewGroup.layout(ViewGroup.java:5108) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1959) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1813) at android.widget.LineCopy the code

Array out of bounds? NoNoNo. The whole log, are not involved in our code, temporarily let a person also feel confused, after some access to data only to find that the forum has been fried pot. Is this bug the fault of Google programmers?

This Bug is caused by the inconsistency between the collections bound by Adapter and RecyclerView.

Get straight to the solution

Found the crux of the problem to solve the solution is also very simple, and listen to me come.

Use notifyDataSetChanged directly to synchronize the external and internal datasets. [Not very recommended]

use notifyDataSetChanged() will avoid this crash, but it will kill Animation and Performance.

This method is relatively simple, but it loses animation and has low performance in updating data. It is also very likely to report this error if you only call notifyDataSetChanged once after more than two operations are performed on the external data set.

Try this Bug directly.

So I’m going to directly duplicate the LinearLauoutManager.

package com.zxedu.ischool.common; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; /** * Author: nanchen * Email: [email protected] * Date: 2017-05-19 15:56 */public class WrapContentLinearLayoutManager extends LinearLayoutManager { public WrapContentLinearLayoutManager(Context context) { super(context); } public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); }}}Copy the code

Yeah, that’s right. Just replace LayoutManaer

// mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); / / to solve RecyclerView possible holder an array Bug mRecyclerView. SetLayoutManager (new WrapContentLinearLayoutManager (this, LinearLayoutManager.VERTICAL, false));Copy the code

Follow the lead and be the most elegant programmer

Now that we know why the crash was sent, we can follow it directly. In the process of data removal and data increase, ensure the consistency of data set removal and data set addition in RecyclerView Adapter.

The internal data set of RecyclerView is called internal data set, and the data set that we pass to Adapter is called external data set. We update the internal data set through the external data set using the following method.

  • notifyItemRangeRemoved()

  • notifyItemRangeInserted()

  • notifyItemRangeChanged()

  • notifyDataSetChanged()

The ‘notifyDataSetChanged()’ method is generally not used because it does not have a default animation effect and is not officially recommended because it is inefficient at updating data.

Don’t call notifyDataSetChanged if you don’t have to.Copy the code

We typically do this when setting data to the Adapter.

public void setData(List<Data> data){
    if(data != null){
        mData.clear();
        mData.addAll(data);
        notifyItemRangeChanged(0,mData.size());
    }
}Copy the code

In fact, there is no problem with this code, but assuming that the data is the data returned by the interface, when the data returned after refreshing is inconsistent with the number of data in the current Adapter, it is very likely to appear the opening bug, directly crash. So we might as well fix it this way.

public void setData(List<Data> data){    if(data != null){        int size = mData.size();
        mData.clear();
        notifyItemRangeRemoved(0,size);
        mData.addAll(data);
        notifyItemRangeInserted(0,mData.size());
    }
}Copy the code

End of story. You might as well have a try.

I am the south dust, only do than the heart of the public number, welcome to pay attention to me.

Recommended reading:

One bonus for Android developers: Free mock interviews

Is “Leaving” the right salary move?

Why do I want to leave?

The correct posture for handing out year-end bonuses


Welcome to pay attention to the public number of Nanchen: Nanchen do not finish the open source, write not to finish the hypothetic, only do than the heart of the public number, if you like, you can choose to share with everyone. If you have a good article, welcome to contribute, let me share with you.Long press the qr code above to pay attention to the open source code, write the hypocrisy of nanchen’s growth notes