Crash cause:

The main reason for this problem is the confusion of RecyclerView data operation. For example, the CRUD methods, such as notifyItemMoved and notifyItemMoved, are called before notifyDataSetChanged is finished, causing data inconsistency. Check carefully to see if there is a problem with the flow of events that operate on the dataset.

Repeat steps:

  1. A Interface RecyclerView list displays some data, such as 10 data
  2. B deleted the recyclerView list data of A interface, for example, there were 7 data left
  3. When you return to interface A, the previous 10 data are still displayed, but more than the current 7 data

Solution:

Catch exceptions

Custom RecyclerView LayoutManager wrapper classes, such as try-catch in the onLayoutChildren() method of the LinearLayoutManager.

import android.content.Context; import android.util.AttributeSet; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; 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

2. Consistent data sets

In the data removal and data increase, need to ensure that RecyclerView Adapter data set and remove, add and other operations after the data set is consistent! In this case, the former is inside the Adapter and is assumed to be called the internal data set, while the latter is passed to the Adapter by the developer and is assumed to be called the external data set. When RecyclerView data is updated, it is necessary to ensure the consistency of external data set and internal data set in real time. External data sets are synchronized to internal data sets using the following methods:

  • notifyItemRangeRemoved();
  • notifyItemRangeInserted();
  • notifyItemRangeChanged();
  • notifyDataSetChanged();

Note that notifyDataSetChange() does not have the default animation effect and is not as efficient as notifyDataSetChange(). It is not recommended.

For example, in RecyclerView Adapter, write a section of abnormal error code, as follows:

public void notifyData(List<PoiItem> poiItemList) { if (poiItemList ! = null ) { mPoiItems.clear(); mPoiItems.addAll(poiItemList); notifyItemRangeChanged(0, poiItemList.size()); }}Copy the code

Error analysis: mPoiItems is an external data set, and two operations are performed on the external data set: remove data, then add data, and then notify data. Here, adding data (the contents of the Adapter’s internal data set before removing data from the external data set) causes an inconsistency between the internal and external data sets. The other side uses notifyItemRangeChanged() to update the data. If the new data passed by the poiItemList is inconsistent with the original mPoiItems, the internal data set and external data are inconsistent after synchronization, resulting in an error. After the above fixes, the code that works normally is as follows:

public void notifyData(List<PoiItem> poiItemList) { if (poiItemList ! = null) { int previousSize = mPoiItems.size(); mPoiItems.clear(); notifyItemRangeRemoved(0, previousSize); mPoiItems.addAll(poiItemList); notifyItemRangeInserted(0, poiItemList.size()); }}Copy the code

Reference:

  • Stackoverflow.com/questions/3…
  • Phantomvk. Making. IO / 2018/04/16 /…
  • www.jianshu.com/p/2eca43386…