Java RecyclerView notifyItemChanged(位置)使应用程序崩溃,并且notifyDataSetChanged()没有动画

Java RecyclerView notifyItemChanged(位置)使应用程序崩溃,并且notifyDataSetChanged()没有动画,java,android,android-recyclerview,notifydatasetchanged,Java,Android,Android Recyclerview,Notifydatasetchanged,因此,我有一个RecyclerView,在我拉入其中的每个xml中都有一个复选框,当按下该复选框时,会从RecyclerView中删除该特定项。至少我是这么想的。据我所知,为了让它工作,我需要使用notifyItemChangedposition;就在底部 但是,当我使用notifyItemChangedposition时;它只会删除正确的项目,如果我按这些顺序中的复选框:1,2,3,4,5或5,4,3,2,1。如果我试图删除第一项,它会删除它,但如果我想删除第三项,它会删除第四项 我发现的另一

因此,我有一个RecyclerView,在我拉入其中的每个xml中都有一个复选框,当按下该复选框时,会从RecyclerView中删除该特定项。至少我是这么想的。据我所知,为了让它工作,我需要使用notifyItemChangedposition;就在底部

但是,当我使用notifyItemChangedposition时;它只会删除正确的项目,如果我按这些顺序中的复选框:1,2,3,4,5或5,4,3,2,1。如果我试图删除第一项,它会删除它,但如果我想删除第三项,它会删除第四项

我发现的另一个选择是使用notifyDataSetChanged;它可以按任何顺序工作,但是不会显示动画

我希望在添加和删除项目时有动画,所以如果有办法使用notifyDataSetChanged实现这一点;我想帮忙

公共类ListAdapter扩展了RecyclerView.Adapter{ SharedPreferences SharedPreferences; 公共静态最终字符串MyPREFERENCES=MyPrefs; 公共静态最终字符串日期=日期; @凌驾 public RecyclerView.ViewHolder OnCreateViewHolderServicewGroup父级,int-viewType{ View-View=LayoutInflater.fromparent.getContext.inflateR.layout.nd_表格,父项,false; 返回新的ListViewHolderview; } @凌驾 public void onBindViewHolderRecyclView.ViewHolder持有人,最终整数适配器位置{ //ListViewHolder.bindViewposition; 字符串数据=hwName.getadapterPosition; 字符串数据2=hwDesc.getadapterPosition; ListViewHolder.mItemText.setTextdata; ListViewHolder holder.mItemText2.setTextdata2; ListViewHolder holder.buttonDelete.SetOnClickListener新建视图.OnClickListener{ @凌驾 公共void onclick视图{ 移除适配器位置; notifyitemchangedapterposition; } }; } @凌驾 公共整数getItemCount{ 返回hwName.size; } 公共类ListViewHolder扩展了RecyclerView.ViewHolder实现了View.OnClickListener{ 私有文本视图mItemText,mItemText2; 公共复选框按钮删除; 公共ListViewHolderView项目视图{ 上级观点; mItemText=TextView itemView.findviewbydr.id.pam\u name; mItemText2=TextView itemView.findViewByIdR.id.pam\u nd; buttonDelete=复选框itemView.findViewByIdR.id.nd\u复选框; itemView.setOnClickListenerthis; } 公共视图位置{ 字符串值=hwName.getposition; 字符串值2=hwDesc.getposition; mItemText.setTextvalue; mItemText2.setTextvalue2; //notifyItemInsertedhwName.size; } 公共void onclick视图{ } } 公共无效删除位置{ hwName.removeposition; hwDesc.removeposition; //改变数据; 通知项目移除位置; 通知项目变更位置; }} 事故报告:

致命异常:主 工艺:com.sajev.slush,PID:14166 java.lang.IndexOutOfBoundsException:索引:5,大小:5 位于java.util.ArrayList.removeArrayList.java:477 位于com.sajev.slush.ListAdapter.removitemlistadapter.java:89 位于com.sajev.slush.ListAdapter$1.onClickListAdapter.java:45 在android.view.view.performClickView.java:5646 在android.widget.CompoundButton.performClickCompoundButton.java:123 在android.view.view$PerformClick.runView.java:22459 位于android.os.Handler.handleCallbackHandler.java:761 在android.os.Handler.dispatchMessageHandler.java:98 在android.os.Looper.Looper.java:156 在android.app.ActivityThread.mainActivityThread.java:6523 在java.lang.reflect.Method.Invokenactive方法中 位于com.android.internal.os.ZygoteInit$MethodAndArgsCaller.runZygoteInit.java:941 com.android.internal.os.ZygoteInit.mainZygoteInit.java:831


有两个问题:

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
    ...
    ((ListViewHolder) holder).buttonDelete.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view){
            removeItem(holder.getAdapterPosition());
        }
    });
}
调用notifyItemRemoved后不调用notifyItemChanged 调用notifyItemRemoved将告诉适配器以前位于位置的项不再存在,这就是您需要做的全部。调用notifyItemChanged会告诉适配器位置处的项已被修改(可能其名称已更改),但没有其他更改,因此在删除项时不使用该项

你会崩溃,因为你把这两个都按顺序调用。假设列表中只有一项,然后将其删除。调用notifyItemRemoved时,适配器现在知道列表中没有项目。但随后调用notifyItemChanged,因此适配器尝试获取第一项。。。但是列表是空的,所以你崩溃了

传递给onBindViewHolder的位置参数不能是最终参数 有关更多信息,请参见~43:10

编译器无法阻止您将final关键字添加到onBindViewHolder的position参数中,但这样做是一个逻辑错误。调用notifyItemRemoved或 如果插入notifyItemInserted,则不会重新绑定其他视图持有者,因此position参数将不再反映实际情况

不要在单击侦听器中使用该位置参数。相反,在运行时查找它。下面是一些考虑到这两个问题的更新代码:

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
    ...
    ((ListViewHolder) holder).buttonDelete.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view){
            removeItem(holder.getAdapterPosition());
        }
    });
}

坠机后logs@ADM好的,donejava.lang.IndexOutOfBoundsException。调试您的代码。@ADM所以我有点理解它崩溃的原因,假设我删除了第一项,第二项也会更新,没有问题,但是如果我现在按删除第三项,它会删除第四项。但如果第四个位置已移动到第三个位置,则hwName.removeposition;和hwDesc.removeposition;与从中删除无关,它会崩溃。我以前就知道,但我只是不知道如何更新一切,比如notifyDataSetChanged;你看到问题还在吗。假设有3个项目,在第一次单击时,我可以毫无问题地删除任何项目,所以假设我首先删除了项目。现在我想移除第二个项目,它已经被移动来代替第一个项目,但是它仍然被视为第二个项目,它调用位置来移除第二个项目,但是因为它被移动到第一个项目的位置,它实际上移除了第三个项目,因为第三个已经移到了第二个的位置。@Sajev我更新了我的答案,以说明为什么不应该在视图持有者事件侦听器中使用final int position。噢,伙计,非常感谢它现在可以工作了,也许你对这个小错误有什么想法。如果我在第一个项目上打勾,那么在另一个项目上打勾的是5个项目,有时是6个项目。它实际上并没有激活移除,只是视觉上的。我不太清楚这是什么原因造成的。@Sajev我最好的猜测是1用户单击复选框2项目被删除3旧的视图支架被回收4回收的视图支架用于显示不同的项目5由于复选框状态在onBindViewHolder中从未取消设置,它从1保留其选中状态您是对的,很好,我现在修复了它。再次感谢: