RecyclerView: Inconsistency detected. Invalid item position
我们的QA检测到一个错误:当旋转Android设备(Droid Turbo)时,发生以下与RecyclerView相关的崩溃:
java.lang.IndexOutOfBoundsException:
Inconsistency detected. Invalid item position 2(offset:2).state:3
对我来说,它看起来像RecyclerView内部的一个内部错误,因为我无法想到这是由我们的代码直接导致的任何方式......
有谁遇到过这个问题?
什么是解决方案?
一个残酷的解决方法可能是在发生异常时捕获异常并从头开始重新创建RecyclverView实例,以避免陷入损坏状态。
但是,如果可能的话,我想更好地理解这个问题(并且可能在其源头修复它),而不是掩盖它。
这个bug很难重现,但是当它发生时它是致命的。
完整的堆栈跟踪:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | 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 |
我有一个(可能)相关的问题 - 使用RecyclerView输入一个活动的新实例,但是使用较小的适配器为我引发了这个崩溃。
在调用
幸运的是,只有在启用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /** * No Predictive Animations GridLayoutManager */ private static class NpaGridLayoutManager extends GridLayoutManager { /** * Disable predictive animations. There is a bug in RecyclerView which causes views that * are being reloaded to pull invalid ViewHolders from the internal recycler stack if the * adapter size has decreased since the ViewHolder was recycled. */ @Override public boolean supportsPredictiveItemAnimations() { return false; } public NpaGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public NpaGridLayoutManager(Context context, int spanCount) { super(context, spanCount); } public NpaGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); } } |
在我的情况下(删除/插入我的数据结构中的数据)我需要清除回收池,然后通知数据集已更改!
mAdapter.notifyDataSetChanged();
在这种情况下,请使用
我有类似的问题,但不完全一样。在我的情况下,1点我正在清理传递给recyclerview的数组
1 | mObjects.clear(); |
而不是调用notifyDataSetChanged,因为我不希望recyclerview立即清除视图。我在AsyncTask中重新填充了mObjects数组。
我通过延迟
我有同样的问题。当我快速滚动并调用API并更新数据时,就会发生这种情况。在尝试所有事情以防止崩溃之后,我找到了解决方案。
1 | mRecyclerView.stopScroll(); |
它会工作。
用户滚动时适配器中的列表清除时会发生此错误,这会使项目持有者的位置发生变化,列表和项目之间的ui丢失,错误发生在下一个
"notifyDataSetChanged"请求。
固定:
查看更新列表方法。如果你做的事情
1 2 3 4 5 6 7 | mainList.clear(); ... mainList.add() or mainList.addAll() ... notifyDataSetChanged(); ===> Error occur |
怎么修。为缓冲区处理创建新的列表对象,然后再次分配给主列表
1 2 3 4 5 6 | List res = new ArrayList(); ….. res.add(); //add item or modify list …. mainList = res; notifyDataSetChanged(); |
感谢Nhan Cao给予了这么大的帮助:)
我和recyclerView有同样的问题
所以我只是在列表清除后立即通知适配器有关数据集的更改。
1 2 3 4 5 | mList.clear(); mAdapter.notifyDataSetChanged(); mList.addAll(newData); mAdapter.notifyDataSetChanged(); |
我正在改变背景
1 2 3 4 5 6 | myRecyclerView.post(new Runnable() { @Override public void run() { myRecyclerAdapter.notifyDataSetChanged(); } }); |
希望能帮助到你
在我修改
代替:
1 2 3 4 5 6 7 8 9 | private class MyAdapter extends RecyclerView.Adapter<ItemHolder> { private List<MyItem> mItems; (....) void setItems(List<MyItem> items) { mItems = items; } } |
我做了:
1 2 3 | void setItems(List<MyItem> items) { mItems = new ArrayList<>(items); } |
使用
1 | notifyDataSetChanged() |
代替
1 | notifyItemRangeInserted(0, YourArrayList.size()) |
在这种情况下。
要解决此问题,请在更新循环视图之前使用空列表调用notifyDataSetChanged()。
例如
1 2 3 | //Method for refresh recycle view if (!hcpArray.isEmpty()) |
hcpArray.clear(); //更新回收视图的列表
1 | adapter.notifyDataSetChanged(); |
您只需要在
1 2 3 4 5 6 7 8 9 10 | // 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 } }); |
我发现当你在拉动刷新期间滚动时会发生这种情况,因为我在
1 2 3 | swipeContainer.setRefreshing(false); //TODO : This is very crucial , You need to clear before populating new items listings.clear(); |
这样你就不会以不一致的方式结束
就我而言,我正在更新项目并在非UI线程中调用
1 2 3 4 5 6 7 | activity.runOnUiThread(new Runnable() { @Override public void run() { changeData(); notifyDataSetChanged(); } }); |
然后它停止了崩溃。
我最近使用新的Android架构组件遇到了这个讨厌的堆栈跟踪。从本质上讲,我的ViewModel中有一个项目列表,我的Fragment使用LiveData观察这些项目。当ViewModel为数据发布新值时,Fragment会更新适配器,传入这些新数据元素并通知适配器已发生更改。
不幸的是,在将新数据元素传递给适配器时,我没有考虑到ViewModel和Adapter都指向同一个对象引用这一事实!这意味着如果我更新数据并从ViewModel中调用
我的修复是在传递给适配器时实例化元素的新副本:
通过这种超级简单的修复,您可以确保在适配器通知之前,适配器数据不会发生变化。
它也可以与同时多次设置适配器有关。我有一个回调方法,同时触发了5-6次,我在回调中设置了适配器,因此RecycledViewPool无法同时处理所有这些数据。这是一个很大的机会,但无论如何你最好还是检查一下。
在我的情况下,我试图在后台线程上更改我的适配器内容,但在main / ui线程上调用notify *。
这是不可能的!强制通知主线程的原因是recyclerview希望您在主线程上编辑后备适配器,即使在同一个调用堆栈上也是如此。
要解决此问题,请确保在ui /主线程上对适配器以及每个notify ...调用进行每次操作!
在我的情况下,我只是用
在通知之前,只需删除布局管理器的所有视图。喜欢:
1 | myLayoutmanager.removeAllViews(); |
我遇到了同样的情况。
在清除收藏之前,通过添加代码解决了问题。
我遇到了一个类似的问题,只是想出来了。我为测试用例硬编了几个例子,但没有确保他们每个都返回一个唯一的ID,这导致了我的下面崩溃。修复ID解决了问题,希望这有助于其他人!
当您尝试清除列表时可能会发生此问题,如果您要清除数据列表,尤其是当您使用pull to refresh尝试使用布尔标志时,将其初始化为false并在OnRefresh方法中将其设置为true,清除dataList如果flag在将新数据添加到它之前为true,则之后将其设为false。
你的代码可能是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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() ; } } |
响应很晚,但这可能有助于某人的功能。
确保您的onStop或onPause方法没有清除任何列表
对我来说,添加这行代码后它起作用了:
1 | mRecyclerView.setItemAnimator(null); |
我解决了这个问题,在获取新数据时逐个添加项目。我在适配器内使用此功能。
1 2 3 4 5 6 7 | public void add(Data item) { if(!params.contains(item){ params.add(item); notifyItemInserted(getItemCount() - 1); } } } |
这只是解决方案,即使从上述解决方案中尝试了很多,也对我有用。
1.)使用
1 2 3 | CustomAdapter scrollStockAdapter = new CustomAdapter(mActivity, new ArrayList<StockListModel>()); list.setAdapter(scrollStockAdapter); scrollStockAdapter.updateList(stockListModels); |
2.)在适配器中写入此方法
1 2 3 4 5 | public void updateList(List<StockListModel> list) { stockListModels.clear(); stockListModels.addAll(list); notifyDataSetChanged(); } |
stockListModels - >此列表是您在适配器中使用的。
抱歉迟到但完美的解决方案:
当您尝试删除特定项目时,只需调用notifydatasetchange()
并在bindviewholder中获取这些项目并删除该项目并再次添加到列表的最后一个,然后如果这是最后一个索引则删除列表位置然后删除项目。
基本上问题出在你试图从中心删除项目时。如果你从上一个索引中删除项目,那么就没有更多的回收,而且你的adpter计数是mantine(这是关键点崩溃来到这里)并且崩溃解决了下面的代码片段。
1 2 3 4 5 6 7 8 | holder.itemLayout.setVisibility( View.GONE );//to hide temprory it show like you have removed item Model current = list.get( position ); list.remove( current ); list.add( list.size(), current );//add agine to last index if(position==list.size()-1){// remove from last index list.remove( position ); } |
我找到
设置
mRecycler.setLayoutFrozen(真);
在swipeContainer的onRefresh方法中。
为我解决了这个问题。
1 2 3 4 5 6 7 8 | swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { orderlistRecycler.setLayoutFrozen(true); loadData(false); } }); |
这是一个非常讨厌的错误。
为了处理我的项目点击,我使用了
在多次刷新
基于此,我删除了
1 2 3 4 5 6 7 8 9 10 11 12 | public void onBindViewHolder (final BaseContentView holder, final int position) { holder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick (View view) { // do whatever you like here } }); } |
这可能不是最好的解决方案,但现在是无崩溃的..希望这会节省你一些时间:)。
我曾经也得到了错误:
原因:我试图从异步任务更新Recycler View,同时尝试获取旧的已删除的viewHolders;
代码:按下按钮生成数据,逻辑如下
问题:每当我在生成数据之前快速滚动我就会得到
Inconsistency detected. Invalid view holder adapter positionViewHolder
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 20(offset:2).state:3
解决方案:不是在生成数据之前清除RecyclerView,而是将其保留,然后将其替换为新数据,即Call NotifyDatasetChanged,如下所示;
1 2 3 4 5 6 7 | @Override protected void onPostExecute(List<Objects> o) { super.onPostExecute(o); recyclerViewAdapter.setList(o); mProgressBar.setVisibility(View.GONE); mRecyclerView.setVisibility(View.VISIBLE); } |
add_location.removeAllViews();
1 2 3 4 5 | 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(); |
当我没有识别时,我遇到了问题我同时使用不同的线程调用了两次。
notifyDataSetChanged
一个来自sqlite加载函数一个来自调用函数
林特给了我一个关于不一致的建议:
我写了(onBindViewHolder()):
1 2 3 4 5 6 | pholder.mRlayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { doStuff(position); } }); |
必须替换为:
1 2 3 4 5 6 | pholder.mRlayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { doStuff(pholder.getAdapterPosition()); } }); |
在您的代码中运行两个代码,然后运行Lint进行完整的解释!
我以前遇到过同样的问题。终于找到了解决方法
我所做的是通知适配器该项目已删除,然后通知适配器数据集范围已更改
1 2 3 4 5 6 7 8 9 | 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()); } |