Cannot call this method while RecyclerView is computing a layout or scrolling when try remove item from recyclerview

AndroidAndroid Recyclerview

Android Problem Overview


I am Trying to remove my item from recyclerview, but i always getting error

> java.lang.IllegalStateException: Cannot call this method while > RecyclerView is computing a layout or scrolling

i am using notify datasetchanged, can i solve this?

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

        }
    }
}

Android Solutions


Solution 1 - Android

Below answer worked for me

This is just workaround for the problem.

This usually occurs when you are calling notifyDataSetChanged() on the background thread. So just move notify to UI thread

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

> You use your RecyclerView instance and inside the post method a new Runnable added to the message queue. The runnable will be run on the user interface thread. This is a limit for Android to access the UI thread from background (e.g. inside a method which will be run in a background thread). for more you run it on UI thread if you needed.

For more you can run it on UI thread, if you needed

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

Solution 2 - Android

This is useful when select All checkbox on click of top checkbox in recyclerview.

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

Solution 3 - Android

If you are tyring to notify recylew item then use isComputingLayout method:

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

Solution 4 - Android

There are two methods you need for this to work:

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

Solution 5 - Android

You are notifying about item change inside onBindViewHolder() method, when your item in process of construction. Most probably you can just improve your logic, to avoid this.

Solution 6 - Android

I give you another idea for solve your problem. I think it could be better The idea is we do not remove invalid data inside onBindViewHolder, we will remove it before

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

}

Solution 7 - Android

When recycler view is computing layout,if we try to notify item change or data change, this issue occurs. But as per official documentation,it is written as

It is very unlikely that your code will be running during state(isComputingLayout) as it is called by the framework when a layout traversal happens or RecyclerView starts to scroll in response to system events (touch, accessibility etc).

But sometimes this issue happens leading to crash.So,better to follow as below.

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

Solution 8 - Android

The method that worked for me the best is this

    if (this@[AdapterName].hasStableIds()) 
    {
         notifyItemChanged(position) 
    }

It check whether the id's has been set or not then only it updates the position

Solution 9 - Android

just override this 2 fun in your recycler view

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

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

Solution 10 - Android

For some reason, doing

recyclerView.post(new Runnable() {
              @Override
              public void run() {
                adapter.notifyDataSetChanged();
              }
            });

didn't work for me. I had to use postDelayed function to finally make it work for my scenario.

recyclerView.postDelayed(
    () -> adapter.notifyItemChanged(itemChangedIndex)),
    500
);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDenny KurniawanView Question on Stackoverflow
Solution 1 - AndroidSagarView Answer on Stackoverflow
Solution 2 - AndroidRakeshView Answer on Stackoverflow
Solution 3 - AndroidSharanjeet KaurView Answer on Stackoverflow
Solution 4 - AndroidCodeversedView Answer on Stackoverflow
Solution 5 - AndroidsnersesyanView Answer on Stackoverflow
Solution 6 - AndroidLinhView Answer on Stackoverflow
Solution 7 - AndroidTarun AView Answer on Stackoverflow
Solution 8 - AndroidAishik kirtaniyaView Answer on Stackoverflow
Solution 9 - AndroidAmirKamView Answer on Stackoverflow
Solution 10 - AndroidDhunju_likes_to_LearnView Answer on Stackoverflow