Java RecyclerView:检测到不一致。无效的项目位置。原因-使用计时器删除项目

Java RecyclerView:检测到不一致。无效的项目位置。原因-使用计时器删除项目,java,android,listview,android-recyclerview,Java,Android,Listview,Android Recyclerview,在继续之前,我在谷歌上搜索了这个bug,我找到了很多答案,但我的情况与他们的情况不同 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3 我正在使用recyclerview显示投票问题,每个问题都有一个计时器,当计时器用完时,项目将从列表中删除 当计时器用完时会发生异常,但只有在很少的情况下,剩余时间(例如100毫秒)会更少。因此,在这种情况

在继续之前,我在谷歌上搜索了这个bug,我找到了很多答案,但我的情况与他们的情况不同

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3
我正在使用recyclerview显示投票问题,每个问题都有一个计时器,当计时器用完时,项目将从列表中删除

当计时器用完时会发生异常,但只有在很少的情况下,剩余时间(例如100毫秒)会更少。因此,在这种情况下,可能是recyclerview正在膨胀物品,同时,计时器会发出警报,recyclerview会尝试移除该物品

错误是当计时器删除项目时,我得到异常

所以我在移除数据集中的元素后解决了这个问题,此时轮询只剩下1秒或更少的时间。所以它不会在列表中添加项,这将运行计时器

如果你想产生这个bug,只需在中启动倒计时
bindView
一旦计时器用完,移除该特定项。 你必须使计时器低于500毫秒

所以现在一切都很完美。解决了一个罕见场景的崩溃问题,但即使剩下的时间更少,我也不想从数据集中删除该元素。请为我提供此错误的正确解决方案。

编辑

更新 这是适配器代码

public class PollAdapter extends RecyclerView.Adapter<PollAdapter.PollViewHolder> {

    // .... 

    @Override
    public void onBindViewHolder(@NonNull PollViewHolder holder, int position) {

    // ...

        if (holder.countDownTimer != null) {
            holder.countDownTimer.cancel();
        }

        // CountDown to set Timer in poll
        holder.countDownTimer = new CountDownTimer(<Timer to be finished.>, 1000) {

            public void onTick(long millisUntilFinished) {
                holder.time.setText("<Remaining time>");
            }

            public void onFinish() {
                removeAt(holder.getAdapterPosition());
            }

        }.start();
    }

    @Override
    public int getItemCount() {
        return pollList.size();
    }

    // To Remove Poll after Time finished
    public void removeAt(int position) {
    pollList.remove(position);
        notifyItemRemoved(position);
    }
}
公共类PollAdapter扩展了RecyclerView.Adapter{ // .... @凌驾 public void onBindViewHolder(@NonNull PollViewHolder,int位置){ // ... if(holder.countDownTimer!=null){ holder.countDownTimer.cancel(); } //倒计时以在轮询中设置计时器 holder.countDownTimer=新的倒计时(,1000){ 公共void onTick(长毫秒未完成){ holder.time.setText(“”); } 公共无效onFinish(){ 移除(holder.getAdapterPosition()); } }.start(); } @凌驾 public int getItemCount(){ 返回pollList.size(); } //在时间结束后删除轮询的步骤 公共无效删除(内部位置){ 删除(位置); 已移除(位置)的项目; } }
此问题主要由职位问题引起

如果你删除了一个职位或进行了任何更改调用notifydatasetchanged,那么只有更改才会发生

简单地说,如果不调用notydatasetchanged,则删除帖子或清除数组,则recyclerview将保持帖子初始化

如果有一个数据数组,我只是清除了该数组并尝试滚动recyclerview。将显示此问题,因为未调用notydatasetchanged。(回收器视图有位置,但未找到阵列位置)


注意:很抱歉我的英语不好

当未通知
RecyclerView
适配器
进行更改时,会出现此错误

要解决此错误,请在底层
适配器中查找数据正在更改的所有点
没有直接的解决方案,因为这是由
RecyclerView引发的内部崩溃

你能做的是:


  • 由于您正在添加,请在添加时调用
    notifyItemInserted
  • 由于您也要删除,因此在删除时请调用
    notifyItemRemoved

  • 要在不进行任何优化的情况下进行测试,您还可以同时调用
    notifyDataSetChanged

    @Moinkhan尝试在onBindViewHolder中添加holder.setIsRecyclable(false)

    使用自定义
    LinearLayoutManager

    public class CustLinearLayoutManager extends LinearLayoutManager {
    
    public CustLinearLayoutManager(Context context) {
        super(context);
    }
    
    public CustLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }
    
    public CustLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    
    // Something is happening here
    
    @Override
    public boolean supportsPredictiveItemAnimations() {
        return false;
      }
    }
    
    使用:-


    我希望它能工作

    这似乎是同时添加和删除项目的情况。我认为,它可以通过顺序执行所有任务来解决。由于您的代码彼此不相关,我建议您使用
    recycler.post(newrunnable(){})并将代码放入
    run()
    方法中,添加/删除元素,然后
    notifyDatasetChanged()
    应在此
    run()
    方法中完成。让我知道结果。

    我也有类似的问题。我有5台设备,只有一台设备出错(联想-k6,牛轧糖7.0)。它在其他牛轧糖手机上运行。这是一个特定于设备的错误

    在活动A>活动B的导航中, 正在调用活动A的onDestroy()。 在onDestroy()中,我正在清除我的静态数组列表。[这只发生在lenovo-k6,牛轧糖7.0中]

    由于我通知适配器的列表为空,所以在活动B中的recyclerView上滚动时出错


    希望它能帮助别人。

    问题可能与适配器有关。如果您使用的是
    setHasStableIds(true)
    在适配器构造函数中,您需要确保正在使用

    确保在适配器中正确覆盖
    getItemId
    。 应该是:

    @Override
    public long getItemId(int position) {
       return yourList == null ? 0 : yourList.get(position).getId();
    }
    
    而非

    @Override
    public long getItemId(int position) {
         return position;
    }
    

    出现此错误是因为在设置recyclerview和adapter时,我放弃删除这行代码:

    mRecyclerView.setHasFixedSize(true);
    

    您不能具有固定大小并删除或添加或具有可筛选回收视图(带搜索)。请检查代码中的那一行。

    很抱歉,我已经知道NotifyDataSetchManaged用于更新recyclerview。我已经这么做了。我尝试了
    notifyItemRemoved()。但是我没有使用
    notifyItemAdded()
    我会尝试一下,然后再给你回复。当然,记住,你必须从两个位置调用它,添加和删除,最好是更改。适配器应始终具有最新的数据。它有时会失败,只是因为当RecycleView检查不一致时失败。没有像
    notifyItemAdded()
    notifyItemInserted
    这样的方法在键入时不使用IDE,因此可能会发生名称不匹配。我尝试了
    notifyItemRangeSerted
    notifyItemInserted
    ,但是
    @Override
    public long getItemId(int position) {
         return position;
    }
    
    mRecyclerView.setHasFixedSize(true);