android java lang - RecyclerView: Inconsistency detected. Invalid item position
Our QA has detected a bug: when rotating the Android device (Droid Turbo), the following RecyclerView-related crash happened:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3
To me it looks like an internal error inside RecyclerView, as I can't think of any way of this being caused directly by our code...
Has anyone encountered this problem?
What would be the solution?
A brutal workaround could be perhaps to catch the exception when it happens, and re-create the RecyclverView instance from scratch, to avoid getting left with a corrupted state.
But, if possible, I would like to understand the problem better (and perhaps fix it at its source), instead of masking it.
The bug is not easy to reproduce, but it is fatal when it happens.
The full stack-trace:
>W/dalvikvm( 7546): threadid=1: thread exiting with uncaught exception (group=0x41987d40)
>E/AndroidRuntime( 7546): FATAL EXCEPTION: main
>E/AndroidRuntime( 7546): Process: com.oblong.mezzedroid, PID: 7546
>E/AndroidRuntime( 7546): java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3
>E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3382)
>E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340)
>E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810)
>E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1306)
>E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269)
>E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523)
>E/AndroidRuntime( 7546): at org.liboid.recycler_view.RecyclerViewContainer$LiLinearLayoutManager.onLayoutChildren(RecyclerViewContainer.java:179)
>E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1942)
>E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
>E/AndroidRuntime( 7546): at org.liboid.recycler_view.LiRecyclerView.onLayout(LiRecyclerView.java:30)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
>E/AndroidRuntime( 7546): at com.oblong.mezzedroid.workspace.content.bins.BinsContainerLayout.onLayout(BinsContainerLayout.java:22)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
>E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
>E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
>E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
>E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
>E/AndroidRuntime( 7546): at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2132)
>E/AndroidRuntime( 7546): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1872)
>E/AndroidRuntime( 7546): at andro
I solved this by delaying the mRecycler.setAdapter(itemsAdapter)
till after adding all the items to the adapter with mRecycler.addAll(items)
and it worked. No idea why i did that to begin with, it was from a library's code that I looked over and saw those lines in the "wrong order", I'm pretty sure this is it though, please if someone can confirm it explain why it's so? Not sure if this is a valid answer even
I have same issue .It was occur when I was scrolling fast and calling API and updating data.After trying all things to prevent crash , I found solution.
mRecyclerView.stopScroll();
It will work.
For fix this issue just call notifyDataSetChanged() with empty list before updating recycle view.
For example
//Method for refresh recycle view
if (!hcpArray.isEmpty())
hcpArray.clear();//The list for update recycle view
adapter.notifyDataSetChanged();
In my case, I was updating the items and calling notifyDataSetChanged
in a non-UI thread. Most of the time it worked, but when a lot of changes happened quickly, it'd crash. When I did, instead, basically
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
changeData();
notifyDataSetChanged();
}
});
then it stopped crashing.
You only need to clear your list on OnPostExecute()
and not while doing Pull to Refresh
// Setup refresh listener which triggers new data loading
swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
AsyncTask<String,Void,String> task = new get_listings();
task.execute(); // clear listing inside onPostExecute
}
});
I discovered that this happens when you scroll during a pull to refresh, since I was clearing the list before the async task
, resulting to java.lang.IndexOutOfBoundsException: Inconsistency detected.
swipeContainer.setRefreshing(false);
//TODO : This is very crucial , You need to clear before populating new items
listings.clear();
That way you won't end with an inconsistency
this problem may happen when you try clearing your list, if you are going to clear your data list especially when you are using pull to refresh try to use a boolean flag, initialize it as false and inside OnRefresh method make it true, clear your dataList if flag is true just before adding the new data to it and after that make it false.
your code might be like this
private boolean pullToRefreshFlag = false ;
private ArrayList<your object> dataList ;
private Adapter adapter ;
public class myClass extend Fragment implements SwipeRefreshLayout.OnRefreshListener{
private void requestUpdateList() {
if (pullToRefresh) {
dataList.clear
pullToRefreshFlag = false;
}
dataList.addAll(your data);
adapter.notifyDataSetChanged;
@Override
OnRefresh() {
PullToRefreshFlag = true
reqUpdateList() ;
}
}
I've faced with the same situation. And it was solved by adding codes before you clear your collection.
mRecyclerView.getRecycledViewPool().clear();
In my case I just removed line with setHasStableIds(true);
I solved the issue, adding items one by one when it gets new data. I use this function inside adapter.
public void add(Data item) {
if(!params.contains(item){
params.add(item);
notifyItemInserted(getItemCount() - 1);
}
}
}
I had a same issue previously. Finally found a workaround for that
What i do is to notify adapter that item has removed and then notify adapter data set range changed
public void setData(List<Data> dataList) {
if (this.dataList.size() > 0) {
notifyItemRangeRemoved(0, dataList.size());
this.dataList.clear();
}
this.dataList.addAll(dataList)
notifyItemRangeChanged(0, dataList.size());
}
i once got the error too:
Cause: I was trying to update a Recycler View from an Async task while simultaneously trying to get old deleted viewHolders;
Code: I generate data at the press of a button, logic as follows
- Clear the last items in the recycler view
- Call async task to generate data
- OnPostExecute Update the Recycler view and NotifyDataSetChanged
Problem: Whenever i scroll fast before generating my data i get
Inconsistency detected. Invalid view holder adapter positionViewHolder java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 20(offset:2).state:3
Solution: instead of clearing the RecyclerView before generating my data, i instead leave it and then Replace it with the New Data, the Call NotifyDatasetChanged, as shown below;
@Override
protected void onPostExecute(List<Objects> o) {
super.onPostExecute(o);
recyclerViewAdapter.setList(o);
mProgressBar.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
}
Just remove all views of your layout Manager before notify. like:
myLayoutmanager.removeAllViews();
add_location.removeAllViews();
for (int i=0;i<arrayList.size();i++)
{
add_location.addView(new HolderDropoff(AddDropOffActivtity.this,add_location,arrayList,AddDropOffActivtity.this,this));
}
add_location.getAdapter().notifyDataSetChanged();
This is only solution which worked for me even trying many from above solutions.
1.) Intilization
CustomAdapter scrollStockAdapter = new CustomAdapter(mActivity, new ArrayList<StockListModel>());
list.setAdapter(scrollStockAdapter);
scrollStockAdapter.updateList(stockListModels);
2.) Write this method in adapter
public void updateList(List<StockListModel> list) {
stockListModels.clear();
stockListModels.addAll(list);
notifyDataSetChanged();
}
stockListModels -> this list is which you are using in adapter .