Android 尝试从RecyclerView中删除项时,RecyclerView正在计算布局或滚动时无法调用此方法

Android 尝试从RecyclerView中删除项时,RecyclerView正在计算布局或滚动时无法调用此方法,android,android-recyclerview,Android,Android Recyclerview,我正试图从recyclerview中删除我的项目,但我总是遇到错误 java.lang.IllegalStateException:无法在 RecyclerView正在计算布局或滚动 我正在使用notify datasetchanged,我可以解决此问题吗 public class AdapterIntransit extends RecyclerView.Adapter<AdapterIntransit.ViewHolder> { private Context conte

我正试图从recyclerview中删除我的项目,但我总是遇到错误

java.lang.IllegalStateException:无法在 RecyclerView正在计算布局或滚动

我正在使用notify datasetchanged,我可以解决此问题吗

public class AdapterIntransit extends RecyclerView.Adapter<AdapterIntransit.ViewHolder> {
    private Context context;
    List<DataIntransit> data;

    public AdapterIntransit(Context context, List<DataIntransit> data) {
        this.context = context;
        this.data = data;
    }

    @Override
    public AdapterIntransit.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardintransit, parent, false);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(AdapterIntransit.ViewHolder holder, int position) {
        if (data.get(position).getJml1() - data.get(position).getJml2() <= 0) {
            data.remove(position);
            notifyItemRemoved(position);
            notifyItemRangeChanged(position, getItemCount());
            notifyDataSetChanged();
        } else {
            holder.kode.setText(data.get(position).getKode());
            holder.nama.setText(data.get(position).getNama());
            holder.jumlah.setText(String.valueOf(data.get(position).getJml1() - data.get(position).getJml2()));
        }
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
    public class ViewHolder extends RecyclerView.ViewHolder{
        TextView kode, nama, jumlah;
        public ViewHolder(View itemView) {
            super(itemView);
            kode = (TextView)itemView.findViewById(R.id.kode);
            nama = (TextView)itemView.findViewById(R.id.nama);
            jumlah = (TextView)itemView.findViewById(R.id.jumlah);

        }
    }
}
公共类适配器Transit扩展了RecyclerView.Adapter{
私人语境;
列出数据;
公共交通适配器(上下文、列表数据){
this.context=上下文;
这个数据=数据;
}
@凌驾
public AdapterTransit.ViewHolder onCreateViewHolder(视图组父级,int-viewType){
View itemView=LayoutInflater.from(parent.getContext()).inflate(R.layout.cardintransit,parent,false);
返回新的ViewHolder(itemView);
}
@凌驾
BindViewHolder上的公共无效(AdapterTransit.ViewHolder,内部位置){

如果(data.get(position).getJml1()-data.get(position).getJml2()我给你另一个解决问题的方法。我认为它会更好 我们的想法是,我们不会删除
onBindViewHolder
中的无效数据,我们会在之前删除它

public AdapterIntransit(Context context, List < DataIntransit > data) {
    this.context = context;
    this.data = removeInValidData(data);
}

private void removeInValidData(List < DataIntransit > data) {
    for (int position = 0, position < data.size(); position++) {
        if (data.get(position).getJml1() - data.get(position).getJml2() <= 0) {
            data.remove(position);
        }
    }
}

@Override
public void onBindViewHolder(AdapterIntransit.ViewHolder holder, int position) {
    holder.kode.setText(data.get(position).getKode());
    holder.nama.setText(data.get(position).getNama());
    holder.jumlah.setText(String.valueOf(data.get(position).getJml1() - data.get(position).getJml2()));

}
公共适配器传输(上下文,列表data){ this.context=上下文; this.data=removeInValidData(数据); } 私有void removeInValidData(列表数据){ 对于(int position=0,position下面的答案对我有用

这只是问题的解决方法

这通常发生在您在
后台线程
上调用
notifyDataSetChanged()
时。因此只需将notify移动到
UI线程

dialeecyclerView.post(new Runnable()
            {
                @Override
                public void run() {
                myadapter.notifyDataSetChanged();
            }
            });
您使用您的
RecyclerView
实例,并在post方法中向消息队列添加一个新的Runnable。Runnable将在用户界面线程上运行。这是Android从后台访问
UI
线程的限制(例如,在将在后台线程中运行的方法中)。 如需了解更多信息,请在
UI
线程上运行它

如果需要,您可以在
UI
线程上运行它

 runOnUiThread(new Runnable(){
 public void run() {
      // UI code goes here
 }
 });

当在recyclerview中单击顶部复选框时选中所有复选框时,这非常有用

recyclerview.post(new Runnable()
{
     @Override
     public void run() {
         myadapter.notifyDataSetChanged();
     }
});

当您的项目处于构建过程中时,您正在
onBindViewHolder()
方法中通知项目更改。很可能您可以改进逻辑以避免此情况。

如果您正在通知recylew项目,则使用isComputingLayout方法:

if (!mRecyclerView.isComputingLayout()) 
{
 // add your code here
}

您需要两种方法来实现此功能:

if (!rv.isComputingLayout && rv.scrollState == SCROLL_STATE_IDLE) {
   rv.adapter?.notifyDataSetChanged()
}

我只是像贝娄那样推迟了

        new Handler().postDelayed(() ->  notifyDataSetChanged(), 1000);

当recycler视图正在计算布局时,如果我们试图通知项目更改或数据更改,则会发生此问题。但根据官方文档,它被写为

当布局遍历发生或RecyclerView开始滚动以响应系统事件(触摸、可访问性等)时,代码不太可能在框架调用的状态(isComputingLayout)期间运行。

但有时这个问题会导致崩溃。所以,最好按照下面的说明进行操作

if (isComputingLayout(recyclerView).not()) {
     if (Looper.myLooper() != Looper.getMainLooper()) {
          // If BG thread,then post task to recycler view
         recyclerView?.post { notifyItemChanged(position, obj) }
     } else {
         notifyItemChanged(position, obj)
     }
}

您能解释一下为什么需要删除
onBindViewHolder
中的项目吗?我想您可以简单地说,不要将它添加到您的RecyclerView@PhanVanLinh,我想是因为,我可以从
onBindViewHolder
访问位置,谢谢您的回答,但我不能从那里访问位置。只需没有为什么代码可以解决这个问题的想法不是很有帮助。请解释你的解决方案背后的想法。@Janusz谢谢。更新了答案。我过去认为,如果人们已经阅读了问题+检查日志+检查我的答案,人们会得到这个答案的想法。这个解决方案只有在你想在项目建设时过滤数据时才有效Adapter这似乎是RecyclerView库中的一个错误,当快速连续(50毫秒内)调用
notifyDataSetChanged()
或在滚动时调用它时,即使在
onBindViewHolder()
之外调用它。例如,使用
notifyDataSetChanged()刷新整个列表时会发生此错误
,不一定要添加或删除项。
Runnable
建议效果很好。这里有一个错误报告:一般来说,为UI做一些依赖于时间的事情是个坏主意。这会起作用,但它是一个闩锁,而不是一个解决方案。原因之一可能是您的视图保持架中有一个可以动画的视图。可能是这样的一个开关,在你切换之后,你调用了
notify…
@Sermilion:是的,我有一个开关&切换它,我做一些操作&然后通知。上面的解决方案对它有效吗?@AndroidGuy这会有效,但这不是正确的方法。如果你有一个开关,并且你手动切换它,不要通知。开关将启动动画它自己的,您就完成了。如果您想通过编程更改开关的状态,那么您需要通知,并且开关在通知后会更改。如果它正在计算布局,那么来自代码的请求将永远无法完成?处理程序不是最佳解决方案