RecyclerView:检测到不一致。无效项位置

我们的QA检测到一个错误:当旋转Android设备(Droid Turbo)时,发生了以下RecyclerView-related崩溃:

< p > java.lang.IndexOutOfBoundsException: 不一致。无效的项目位置2(偏移量:2).state:3

对我来说,它看起来像一个内部错误在RecyclerView,因为我不能想到这是由我们的代码直接引起的任何方式…

有人遇到过这个问题吗?

解决方案是什么?

一个残酷的解决方法可能是在异常发生时捕获异常并从头重新创建RecyclverView实例,以避免留下损坏的状态。

但是,如果可能的话,我希望更好地理解这个问题(也许从根源上解决它),而不是掩盖它。

这种细菌不容易繁殖,但一旦发生就会致命。

完整的堆栈跟踪:

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
162570 次浏览

我通过延迟mRecycler.setAdapter(itemsAdapter)来解决这个问题,直到用mRecycler.addAll(items)将所有项添加到适配器之后,它才工作。不知道我为什么这么做,这是从一个库的代码,我看了看,看到这些行在“错误的顺序”,我很确定这是它,如果有人能证实它,请解释为什么是这样?甚至不确定这是否是一个有效的答案

在这种情况下,使用notifyDataSetChanged()代替notifyItem...

我有一个(可能)相关的问题-进入一个新的实例的活动与RecyclerView,但与一个较小的适配器触发这个崩溃为我。

RecyclerView.dispatchLayout()可以在调用mRecycler.clearOldPositions()之前尝试从废料中提取项目。结果是从公共池中提取位置高于适配器大小的项。

幸运的是,它只在启用PredictiveAnimations时才会这样做,所以我的解决方案是子类GridLayoutManager (LinearLayoutManager有同样的问题并“修复”),并重写supportsPredictiveItemAnimations()以返回false:

/**
* 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);
}
}

我解决了这个问题,当它得到新数据时,一个接一个地添加项目。我在适配器内部使用这个函数。

public void add(Data item) {
if(!params.contains(item){
params.add(item);
notifyItemInserted(getItemCount() - 1);
}
}
}

我也遇到过类似的问题,但不完全一样。在我的例子中,我在1点清除传递给recyclerview的数组

mObjects.clear();

并且不调用notifyDataSetChanged,因为我不希望recyclerview立即清除视图。我在AsyncTask中重新填充mObjects数组。

在我的情况下(删除/插入数据在我的数据结构),我需要清除回收池,然后通知数据集更改!

< p > <代码> mRecyclerView.getRecycledViewPool () .clear (); mAdapter.notifyDataSetChanged(); < /代码> < / p >

我也有同样的问题。它发生在我快速滚动和调用API和更新数据时。在尝试了所有防止崩溃的方法后,我找到了解决方案。

mRecyclerView.stopScroll();

它会起作用的。

当你尝试清除你的列表时,这个问题可能会发生,如果你要清除你的数据列表,特别是当你使用拉刷新尝试使用一个布尔标志,初始化它为假,在OnRefresh方法使它为真,清除你的dataList如果标志为真之前添加新的数据到它,之后使它为假。

您的代码可能是这样的

 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() ;
}


}

我找到了 设置 mRecycler.setLayoutFrozen(真正的);

.在swipeContainer的onRefresh方法

帮我解决了问题。

swipeContainer.setOnRefreshListener(new   SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
orderlistRecycler.setLayoutFrozen(true);
loadData(false);


}
});

它还可以与在同一时间多次设置适配器有关。我有一个回调方法,在同一时间被触发5-6次,我在那个回调中设置适配器,因此RecycledViewPool不能同时处理所有这些数据。机会不大,但你最好还是去看看。

我以前也遇到过同样的问题。终于找到解决办法了

我所做的是通知适配器,该项目已删除,然后通知适配器数据集范围改变

 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());


}

这是一个相当讨厌的虫子。

为了处理我的项目单击,我使用了RecyclerView.OnItemTouchListener的实现,类似于在这个问题中找到的解决方案。

在多次刷新RecyclerView的数据源并单击一个项目之后,这个IndexOutOfBoundsException将使我的应用程序崩溃。当一个项被单击时,RecyclerView在内部寻找正确的底层视图并返回它的位置。检查源代码,我看到有一些TasksThreads安排。长话短说,基本上这只是一种非法状态,两个数据源混合在一起,没有同步,整个事情就失控了。

基于此,我删除了我的RecyclerView.OnItemTouchListener的实现,并简单地捕捉到自己对AdapterViewHolder的单击:

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
}
});


}

这可能不是最好的解决方案,但目前没有崩溃。希望这将节省你一些时间:)。

我也遇到过同样的情况。 在你清除你的集合之前,通过添加代码来解决这个问题

mRecyclerView.getRecycledViewPool().clear();

在我的例子中,我在一个非ui线程中更新项目并调用notifyDataSetChanged。大多数时候它是有效的,但当大量变化迅速发生时,它就会崩溃。当我这样做的时候,基本上

activity.runOnUiThread(new Runnable() {
@Override
public void run() {
changeData();
notifyDataSetChanged();
}
});

然后它停止了崩溃。

在我修改了Adapter实现以使用items数组的副本而不是引用之后,我的问题就消失了。每次在RecyclerView中显示新项时,都会调用setItems()方法。

而不是:

private class MyAdapter extends RecyclerView.Adapter<ItemHolder> {
private List<MyItem> mItems;


(....)


void setItems(List<MyItem> items) {
mItems = items;
}
}

我做了:

void setItems(List<MyItem> items) {
mItems = new ArrayList<>(items);
}

使用

notifyDataSetChanged()

而不是

notifyItemRangeInserted(0, YourArrayList.size())

在这种情况下。

我正在修改后台ThreadRecyclerView的数据。我得到了与op相同的Exception。我在更改数据后添加了这个:

myRecyclerView.post(new Runnable() {
@Override
public void run() {
myRecyclerAdapter.notifyDataSetChanged();
}
});

希望能有所帮助

我也遇到过类似的问题,只是想办法解决了。我为一个测试用例硬编码了一些示例,但没有确保它们每个都返回唯一的ID,这导致了下面的崩溃。修复id解决了这个问题,希望这能帮助到其他人!

为了解决这个问题,只需在更新循环视图之前调用notifyDataSetChanged(),使用空列表。

例如

//Method for refresh recycle view


if (!hcpArray.isEmpty())

hcpArray.clear();//更新循环视图列表

adapter.notifyDataSetChanged();

在我的例子中,我只是删除了带有setHasStableIds(true);的行

在我的情况下,我试图在后台线程上更改适配器内容,但在主/ui线程上调用notify*。

强制notify到主线程的原因是recyclerview希望你在主线程上编辑备份适配器,甚至在同一个调用堆栈上。

要解决这个问题,请确保对适配器的每个操作以及每个通知…调用是在ui /主线程!

我也有过这样的错误:

原因:我试图从异步任务更新一个回收器视图,同时试图获得旧的已删除的viewHolders;

代码:我在按下按钮时生成数据,逻辑如下

  1. 清除回收器视图中的最后一项
  2. 调用异步任务生成数据
  3. 更新Recycler视图和NotifyDataSetChanged

问题:每当我快速滚动之前生成我的数据,我得到

< p >不一致。无效的视图持有者适配器positionViewHolder java.lang.IndexOutOfBoundsException:检测到不一致。无效的项目位置20(偏移量:2).state:3

解决方案:而不是在生成我的数据之前清除RecyclerView,我而是离开它,然后用新数据替换它,调用NotifyDatasetChanged,如下所示;

       @Override
protected void onPostExecute(List<Objects> o) {
super.onPostExecute(o);
recyclerViewAdapter.setList(o);
mProgressBar.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
}
林特给了我一个关于不一致性的建议: 我写了(onBindViewHolder()):

pholder.mRlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doStuff(position);
}
});

它必须被替换为:

pholder.mRlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doStuff(pholder.getAdapterPosition());
}
});

在你的代码中运行这两个代码,然后运行Lint得到完整的解释!!

只需在通知之前删除布局管理器的所有视图。如:

myLayoutmanager.removeAllViews();

你只需要在OnPostExecute()上清除你的列表,而不是在执行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


}
});

我发现当你在拉动刷新中滚动时,会发生这种情况,因为我在async task之前清除列表,导致java.lang.IndexOutOfBoundsException: Inconsistency detected.

        swipeContainer.setRefreshing(false);
//TODO : This is very crucial , You need to clear before populating new items
listings.clear();

这样你就不会以前后矛盾结束

我有同样的问题与RecyclerView 所以我只是在列表清除后通知适配器关于数据集的变化

mList.clear();
mAdapter.notifyDataSetChanged();


mList.addAll(newData);
mAdapter.notifyDataSetChanged();

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();
抱歉迟到了,但完美的解决方案: 当你试图删除一个特定的项时,只需调用notifydatasetchange() 在bindviewholder中获取这些项,然后删除该项,并再次添加到列表的最后一个索引中,然后检查列表位置,如果这是最后一个索引,那么删除项。 基本上,问题是当你试图从中心删除项目时。如果你从最后一个索引中删除项目,那么就没有更多的回收,而且你的adpter计数是mantine(这是临界点崩溃来这里),崩溃解决了下面的代码片段
 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 );
}

我最近在使用新的Android架构组件时遇到了这种讨厌的堆栈跟踪。从本质上讲,我在ViewModel中有一个项目列表,由我的Fragment使用LiveData观察。当ViewModel发布数据的新值时,Fragment更新适配器,传入这些新的数据元素并通知适配器已经发生了变化。

不幸的是,当将新的数据元素传递给适配器时,我没有考虑到ViewModel和adapter都指向同一个对象引用!这意味着,如果我在ViewModel中更新数据并调用postValue(),就会有一个非常小的窗口,在那里数据可以更新,而适配器还没有被通知!

我的修复是实例化一个新的副本的元素时,传递到适配器:

mList = new ArrayList<>(passedList);

有了这个超级简单的修复,您可以确保您的适配器数据不会改变,直到您的适配器被通知。

这是唯一的解决方案,对我来说,即使尝试了许多以上的解决方案。

1)。Intilization

CustomAdapter scrollStockAdapter =
new CustomAdapter(mActivity, new ArrayList<StockListModel>());
list.setAdapter(scrollStockAdapter);
scrollStockAdapter.updateList(stockListModels);

2)。在适配器中编写此方法

public void updateList(List<StockListModel> list) {
stockListModels.clear();
stockListModels.addAll(list);
notifyDataSetChanged();
}

stockListModels→此列表是您在适配器中使用的列表。

对我来说,在添加了这行代码后,它起作用了:

mRecyclerView.setItemAnimator(null);
此错误发生在用户滚动时适配器中的列表清除,这使得项目holder的位置发生变化,在ui上的列表和项目之间失去了引用,在next中发生错误 “notifyDataSetChanged”< / >强的要求。

解决办法:

检查您的更新列表方法。如果你这样做

mainList.clear();
...
mainList.add() or mainList.addAll()
...
notifyDataSetChanged();


===> Error occur

如何修复。为缓冲区处理创建新的列表对象,然后再次赋值给主列表

List res = new ArrayList();
…..
res.add();  //add item or modify list
….
mainList = res;
notifyDataSetChanged();

感谢铁男曹提供的巨大帮助:)

非常晚的响应,但这可能有助于某些人的功能。

确保你的onStop或onPause方法没有清除任何你的列表

当我没有意识到我同时调用了两次不同的线程时,问题就发生了。

notifyDataSetChanged

一个来自sqlite加载函数,一个来自调用函数后

我设法解决这个问题的一种方法(在Kotlin应用程序与架构组件)是通过设置if (recyclerView.adapter == null) recyclerView.adapter = MyAdapter(datasource)后,我从存储库获取数据。显然,这可能与存储库中挂起函数的异步问题有关,因为当我在启动活动时第一次获取数据时,它调用REST API,因为db中没有数据,一切都很顺利,但在那之后,同样的查询不能再次进行,导致崩溃。

对我来说,这解决了我的问题

rv.setAdapter(null);
rv.setItemAnimator(null);

PS:我的问题发生时,我做搜索过滤器在我的recyclerview适配器

在我的例子中,我得到了这个例外

java.lang.IndexOutOfBoundsException:检测到不一致。无效的视图持有者适配器positionViewHolder

以上答案在我的情况下都不适用。因为我正在更新/更改适配器中的现有项,但我使用了

myAdapter.notifyItemInserted(position)

相反,我应该用这个

myAdapter.notifyItemChanged(position)

注意:插入项时应该使用notifyItemInserted(),更新适配器中的项时应该使用notifyItemChanged()

在调用adapter.submitList(list)之前使用ListAdapter (androidx.recyclerview.widget.ListAdapter)调用adapter.submitList(null):

adapter.submitList(null)
adapter.submitList(someDataList)

这个异常在API 19、21上引发(但不是新的)。在Kotlin协程中,我加载了数据(在后台线程),并在UI线程中添加并显示它们:

adapter.addItem(item)

适配器:

var list: MutableList<Item> = mutableListOf()


init {
this.setHasStableIds(true)
}


open fun addItem(item: Item) {
list.add(item)
notifyItemInserted(list.lastIndex)
}

由于某些原因Android渲染不够快或其他原因,所以,我在RecyclerViewpost方法中更新了一个列表(项目的添加,删除,更新事件):

view.recycler_view.post { adapter.addItem(item) }

此异常类似于“无法在滚动回调中调用此方法”。滚动回调可能在测量期间运行。你不能改变theRecyclerView的数据。任何可能改变RecyclerView结构或适配器内容的方法调用都应该延迟到下一帧。”:Recyclerview -不能在滚动回调中调用此方法

大多数答案是禁用动画或创建新的数据副本,在我看来这是一个过度的。这些方法确实有效,但并没有解决问题的根本原因。在我的例子中,这是由于以错误的方式使用了DiffUtils。在areItemsTheSame(old, new)方法中,我没有正确地实现相等性检查,这反过来导致适配器被notifyItemRangeInserted()通知,即使新列表中有相同数量的项。因此,请密切关注如何实现DiffUtils回调!

扩展LinearLayoutManager并捕获这个错误

public class NoCrashLinearLayoutManager extends LinearLayoutManager {


public NoCrashLinearLayoutManager(Context context) {
super(context);
}


public NoCrashLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}


public NoCrashLinearLayoutManager(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();
}
}
}

如果有人有同样的问题,我在适配器中覆盖了这两个方法,它工作得很好。

        override fun getItemId(position: Int): Long {
return position.toLong()
}
    

override fun getItemViewType(position: Int): Int {
return position
}

我刚刚解决了同样的问题。我设置了RecyclerView.AdaptersetHasStableIds(true),以避免项目闪烁。

我在getItemId()中使用了一个可复制的字段(我的模型没有id字段):

override fun getItemId(position: Int): Long {
// Error-prone due to possibly duplicate name.
return contacts[position].name.hashCode().toLong()
}

getItemId()应该为每个项目返回一个唯一的id,所以解决方案是这样做:

override fun getItemId(position: Int): Long {
// Contact's phone is unique, so I use it instead.
return contacts[position].phone.hashCode().toLong()
}
如果notifyItemChanged(int position), notifyItemInserted(int position) 当您想要更新项时使用notifyItemChanged,而当您想要添加项时使用notifyItemInserted

时,会发生此问题

您可以按以下方式重现此崩溃

  1. 清除适配器项list.clear()。(不调用notify方法)
  2. 滚动回收视图。

因此,我假设当您从列表中删除项目并滚动而没有调用notify方法时发生崩溃

更新RecyclerView到最新的1.2.1版本。奇迹发生了!不能再打破我的应用程序:) 所以. .尝试用gradle文件

中的最新版本号替换旧版本号
dependencies {
...
// RecyclerView
def recyclerview_version = "1.2.1"
implementation "androidx.recyclerview:recyclerview:$recyclerview_version"
}
如果有多个回收器视图共享同一个适配器,则会弹出此错误,为避免此错误,请为这些回收器视图创建单独的适配器。 这使得回收视图具有非共享池,从而在不需要时停止适配器来填充它们

造成这次崩溃的一个可能原因是。

在recyclerview仍在滚动时重新加载数据。

因此,在重新加载数据之前,尝试recyclerview.stopScroll()。