kanytu / android-material-drawer-template

An Android template with navigation drawer for material design
Apache License 2.0
674 stars 217 forks source link

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

Open Jonathan727 opened 9 years ago

Jonathan727 commented 9 years ago

I've seen this crash a few times while using the navigation drawer.

java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
        at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
        at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeChanged(RecyclerView.java:3000)
        at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:7503)
        at android.support.v7.widget.RecyclerView$Adapter.notifyItemChanged(RecyclerView.java:4353)
        at com.company.busscan.navigation.NavigationDrawerAdapter.touchPosition(NavigationDrawerAdapter.java:97)
        at com.company.busscan.navigation.NavigationDrawerAdapter.access$000(NavigationDrawerAdapter.java:24)
        at com.company.busscan.navigation.NavigationDrawerAdapter$1.onTouch(NavigationDrawerAdapter.java:64)

Trace mentions this chunk of code from NavigationDrawerAdapter:

private void touchPosition(int position) {
    int lastPosition = mTouchedPosition;
    mTouchedPosition = position;
    if (lastPosition >= 0)
        notifyItemChanged(lastPosition);
    if (position >= 0)
        notifyItemChanged(position);
}

and the _ACTIONCANCEL case here too:

    viewHolder.itemView.setOnTouchListener(
            new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {

                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            touchPosition(i);
                            return false;
                        case MotionEvent.ACTION_CANCEL:
                            touchPosition(-1);
                            return false;
                        case MotionEvent.ACTION_MOVE:
                            return false;
                        case MotionEvent.ACTION_UP:
                            touchPosition(-1);
                            return false;
                    }
                    return true;
                }
            }
    );

Also, I'm curious whether I should expect any changes now that the support library revision 22 has added new recycler view methods getlayoutPosition() and getadapterPosition()

kanytu commented 9 years ago

Refer to this post to see if it helps:

http://stackoverflow.com/q/27070220/3410697

Which means:

Create a Handler and perform the notifyData calls inside it.

Since I can't reproduce this error I can't help you more. But I'm pretty sure the Handler will resolve the problem

zakiharis commented 9 years ago

Dirty fix :

try {
    notifyItemChanged(lastPosition);
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

Normally, I facing this issue, when open/close drawer multiple times and fast.

amerimi commented 9 years ago

Hello,

Here is a simple way to always reproduce this issue:

@Override
protected void onResume() {
    super.onResume();
    mTimer = new Timer();
    mTimer.schedule(new TimerTask() {
        @Override
        public void run() {
            for (int i = 0; i < mElementsList.size(); i++) {
                Random r = new Random();
                mElementsList.get(i).setFieldValue(r.nextInt(100));
                mAdapter.notifyItemChanged(i);
            }
        }
    }, 0, 1); // calls it faster then it computs the layout
}

Hope it helps

AristoM commented 5 years ago

This will solve your issue new Handler().post(new Runnable() { @Override public void run() { removeAt(position); } });