添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
率性的玉米  ·  视频回放·  9 月前    · 
曾经爱过的机器猫  ·  Excel ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Our QA has detected a bug: when rotating the Android device (Droid Turbo), the following RecyclerView-related crash happened:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3

To me, it looks like an internal error inside RecyclerView, as I can't think of any way of this being caused directly by our code...

Has anyone encountered this problem?

What would be the solution?

A brutal workaround could be perhaps to catch the exception when it happens and re-create the RecyclverView instance from scratch, to avoid getting left with a corrupted state.

But, if possible, I would like to understand the problem better (and perhaps fix it at its source), instead of masking it.

The bug is not easy to reproduce, but it is fatal when it happens.

The full stack-trace:

W/dalvikvm( 7546): threadid=1: thread exiting with uncaught exception (group=0x41987d40)
    E/AndroidRuntime( 7546): FATAL EXCEPTION: main
    E/AndroidRuntime( 7546): Process: com.oblong.mezzedroid, PID: 7546
    E/AndroidRuntime( 7546): java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3382)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1306)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523)
    E/AndroidRuntime( 7546):    at org.liboid.recycler_view.RecyclerViewContainer$LiLinearLayoutManager.onLayoutChildren(RecyclerViewContainer.java:179)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1942)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
    E/AndroidRuntime( 7546):    at org.liboid.recycler_view.LiRecyclerView.onLayout(LiRecyclerView.java:30)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at com.oblong.mezzedroid.workspace.content.bins.BinsContainerLayout.onLayout(BinsContainerLayout.java:22)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2132)
    E/AndroidRuntime( 7546):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1872)
    E/AndroidRuntime( 7546):    at andro
                A question: How consistent is your repro? I know this is an error in google's code here and here. But this can be avoided. So, is this happening on every rotate?
– Vic Vuci
                May 13, 2015 at 16:53
                Rule to remember is: "always notify...() immediately after changing the dataset, and make sure to call it from the same thread".
– Richard Le Mesurier
                Jul 26, 2017 at 12:59

I had a (possibly) related issue - entering a new instance of an activity with a RecyclerView, but with a smaller adapter was triggering this crash for me.

RecyclerView.dispatchLayout() can try to pull items from the scrap before calling mRecycler.clearOldPositions(). The consequence being is that it was pulling items from the common pool that had positions higher than the adapter size.

Fortunately, it only does this if PredictiveAnimations are enabled, so my solution was to subclass GridLayoutManager (LinearLayoutManager has the same problem and 'fix'), and override supportsPredictiveItemAnimations() to return false :

* No Predictive Animations GridLayoutManager private static class NpaGridLayoutManager extends GridLayoutManager { * Disable predictive animations. There is a bug in RecyclerView which causes views that * are being reloaded to pull invalid ViewHolders from the internal recycler stack if the * adapter size has decreased since the ViewHolder was recycled. @Override public boolean supportsPredictiveItemAnimations() { return false; public NpaGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); public NpaGridLayoutManager(Context context, int spanCount) { super(context, spanCount); public NpaGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); This worked for me, and disabling predictive animations doesn't cause you to lose the animations all together. Bravo. – Bob Liberatore Dec 3, 2015 at 21:39 Thank you very much Sir! Worked instantly with LinearLayoutManager, probably saving me days. – levavare Dec 21, 2015 at 10:48 I think this guy deserve we build a statue in honour of his precious help... It's one of the worst documented issue on the web, but it seems lots of dev encounter this issue... I just wonder how did you find it could be skipped if PredictiveAnimations are false, @KasHunt ? Because, the stacktrace is very unclear... – PAD Jul 14, 2016 at 18:46 Anybody knows, how to fix that without this hack? Because notifyDatasetChanged was dropped in favor of DiffUtil – Anton Shkurenko Mar 21, 2018 at 13:02

In my case (delete/insert data in my data structure) I needed to clear recycle pool and then notify data set changed!

mRecyclerView.getRecycledViewPool().clear(); mAdapter.notifyDataSetChanged();

I don't normally say this, BUT THANK YOU SO MUCH. I have tried EVERYTHING to fix this crash which happens sporadically when I'm moving a bunch of items on the list around in rapid order. I've spent literally probably a full week on trying to solve this issue. I walked away from it for a couple of months to try to give my brain a chance to approach it differently, then found this on my first Google attempt. Bless you! – Chantell Osejo Aug 26, 2016 at 20:41 In some cases this is the way to go. I had a situation where I replaced all my items, but I wasn't being honest with the adapter, only telling it I had inserted some new items (notifyItemRangeInserted), without first telling it I had also removed items. The adapter then expected there to be more items then there actually were. If using any of the adapter's notify methods expect notifyDataSetChanged, such as notifyItemRangeRemoved / Inserted / Updated, the caller has the full responsibility of telling the adapter exactly what was changed, or you may end up with this "inconsistent state". – JHH Dec 18, 2015 at 10:04 This is not the way to go. If this works that means you just messed up the range for notifyItem... and correcting that will start working instead of re-rendering all the items. – Ranjan Jul 12, 2018 at 7:13 @Ranjan RecyclerView doesn't "re-rendering all the items", it just renders what is on the screen ("visible") – Farid Feb 3, 2022 at 6:29

I had the same issue with RecyclerView So I just notified the adapter about data set change right after the list cleared.

mList.clear();
mAdapter.notifyDataSetChanged();
mList.addAll(newData);
mAdapter.notifyDataSetChanged();

This error occur when the list in adapter clear when user scrolling which make position of item holder changing, lost ref between list and item on ui, error happen in next "notifyDataSetChanged" request.

Review your update list method. If you do something like

mainList.clear();
mainList.add() or mainList.addAll()
notifyDataSetChanged();
===> Error occur

How to fix. Create new list object for buffer processing and assign again to main list after that

List res = new ArrayList();
res.add();  //add item or modify list
mainList = res;
notifyDataSetChanged();

Thanks to Nhan Cao for this great help :)

I solved this by delaying the mRecycler.setAdapter(itemsAdapter) till after adding all the items to the adapter with mRecycler.addAll(items) and it worked. No idea why i did that to begin with, it was from a library's code that I looked over and saw those lines in the "wrong order", I'm pretty sure this is it though, please if someone can confirm it explain why it's so? Not sure if this is a valid answer even

I think this is the solution, once i delayed the adapter it was fine i believe... now it pops up when set adapter in UI thread and adding items to it. – EngineSense Apr 6, 2016 at 16:00

I have same issue .It was occur when I was scrolling fast and calling API and updating data.After trying all things to prevent crash , I found solution.

mRecyclerView.stopScroll();

It will work.

@Dr.aNdRO : Adapter need to set position and if you continue scrolling recylerview, adapter can't set data which is the cause of the crash. It's not bad UX – Anand Savjani Jan 19, 2018 at 18:12

I had a similar problem but not exactly the same. In my case at 1 point I was clearing the array that was passed to the recyclerview

mObjects.clear();

and not calling notifyDataSetChanged, as I did not want the recyclerview to immediately clear the views. I was re-filling the mObjects array in AsyncTask.

this is not a fix in most cases, if you want animation you have te rewrite your adapter code and find your errors in notifying changes – Dragos Rachieru Mar 21, 2019 at 8:20 It works fine for me.I'm using real adapter so I can't control the flow and I enabled windowActivityTransitions in a style that what cause this issue thanks man you save my day. – Arul May 2, 2020 at 14:59

I am altering data for the RecyclerView in the background Thread. I got the same Exception as the OP. I added this after changing data:

myRecyclerView.post(new Runnable() {
    @Override
    public void run() {
        myRecyclerAdapter.notifyDataSetChanged();

Hope it helps

thanks man! this is the only answer that makes sense from an Android development point of view. – philtz Jan 14, 2020 at 0:19 While I have also solved with the help of view.recycler_view.post, I used notifyItemInserted. In my case it has already been UI thread. – CoolMind Feb 26, 2020 at 12:18

I've faced with the same situation. And it was solved by adding codes before you clear your collection.

mRecyclerView.getRecycledViewPool().clear();

My problem went away after I modified my Adapter implementation to use a copy of the items array instead of a reference. The setItems() method is called each time we have new items to show in the RecyclerView.

Instead of:

private class MyAdapter extends RecyclerView.Adapter<ItemHolder> {
     private List<MyItem> mItems;  
    (....)
    void setItems(List<MyItem> items) {
        mItems = items;

I did:

void setItems(List<MyItem> items) {
    mItems = new ArrayList<>(items);
                @MiguelA.Gabriel this will effect performance? for example in my case i am updating recylerview's array too frequently  so currently i am doing this suggestionsRecyclerView.swapAdapter(new CandidatesAdapter(mSuggestions), true);   and this is my constructor  public CandidatesAdapter(List<String> suggestionsList) {             this.suggestionsList = new ArrayList<>(suggestionsList);         }
– Mateen Chaudhry
                May 17, 2018 at 5:50
                @mateen-chaudhry It probably will. You'll need to test it in your case and decide, or try using another of the proposed solutions. As I said, it is only a workaround and it works for me in my case.
– Miguel A. Gabriel
                May 17, 2018 at 6:59

In my case, I was updating the items and calling notifyDataSetChanged in a non-UI thread. Most of the time it worked, but when a lot of changes happened quickly, it'd crash. When I did, instead, basically

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        changeData();
        notifyDataSetChanged();

then it stopped crashing.

This is only solution which worked for me even trying many from above solutions.

1.) Intilization

CustomAdapter scrollStockAdapter = 
         new CustomAdapter(mActivity, new ArrayList<StockListModel>());
list.setAdapter(scrollStockAdapter);
scrollStockAdapter.updateList(stockListModels);

2.) Write this method in adapter

public void updateList(List<StockListModel> list) {
    stockListModels.clear();
    stockListModels.addAll(list);
    notifyDataSetChanged();

stockListModels -> this list is which you are using in adapter .

But HasStableIds(true) improves the performance of the Rv, is there any alternative solution? – Sreekanth Karumanaghat Mar 20, 2018 at 10:56 Actually I think it could be due to different reasons, so there could be different solutions to this problem based on what is the root cause. – Sreekanth Karumanaghat May 4, 2018 at 7:20

You only need to clear your list on OnPostExecute() and not while doing Pull to Refresh

// Setup refresh listener which triggers new data loading
        swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                AsyncTask<String,Void,String> task = new get_listings();
                task.execute(); // clear listing inside onPostExecute

I discovered that this happens when you scroll during a pull to refresh, since I was clearing the list before the async task , resulting to java.lang.IndexOutOfBoundsException: Inconsistency detected.

        swipeContainer.setRefreshing(false);
        //TODO : This is very crucial , You need to clear before populating new items 
        listings.clear();

That way you won't end with an inconsistency

Using ListAdapter (androidx.recyclerview.widget.ListAdapter) call adapter.submitList(null) before calling adapter.submitList(list):

adapter.submitList(null)
adapter.submitList(someDataList)
                I am also using ListAdapter, but if we submitList(null) and then the actual data list then we are not really utilizing the benefits of ListAdapter
– Gauri Gadkari
                May 25, 2022 at 22:18

extends LinearLayoutManager and catch this error

public class NoCrashLinearLayoutManager extends LinearLayoutManager {
    public NoCrashLinearLayoutManager(Context context) {
        super(context);
    public NoCrashLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    public NoCrashLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        try {
            super.onLayoutChildren(recycler, state);
        } catch (IndexOutOfBoundsException e){
            e.printStackTrace();

You can reproduce this crash in the following way

  • Clear adapter items list.clear(). (Do not call notify*** methods)
  • Scroll recycler view.
  • So I assume this crash happens when you remove items from the list and scroll without calling notify methods

    It also can be related with setting the adapter multiple times at the same time. I had a callback method which was triggered 5-6 times at the same time and I was setting the adapter in that callback so RecycledViewPool couldn't handle with all of those datas contemporaneously. It's a fat chance but you better check it out anyway.

    @RanjithKumar, Kindly share your way to resolve the above issue. I resolved it using mRecyclerView.getRecycledViewPool().clear(); before notifyDataSetChanged and using synchronized block around update function of adapter – Attiq ur Rehman Feb 7, 2018 at 8:08 can you please take a look at my code i think my problem is like yours can you help me stackoverflow.com/questions/50213362/… – Mateen Chaudhry May 9, 2018 at 17:23 but this is not good for performance right? notifyItemRangeInserted is better, the problem does not lie here – Derekyy Sep 14, 2017 at 7:04

    In my case I was trying to change my adapter contents on a background thread but called notify* on the main/ui thread.

    That is not possible! The reason why notify is forced to main thread is that the recyclerview wants you to edit your backing adapter on the main thread, even on the same call stack.

    To solve the problem make sure that every operation to your adapter as well as every notify... call is made on the ui/main thread!

    adding items to the list in your adapter should be done on a background thread and call notify on postexecute. adding of data in ui thread makes the app freeze for some millisecond or seconds if adding many data – dione llorera Sep 1, 2018 at 15:31 agreed with @dionellorera, it should be made clear that a "change in adapter contents" specifically means modifying any data directly, whether primitive values, properties of objects, or objects themselves – OzzyTheGiant Sep 13, 2019 at 16:28

    I ran into this nasty stack trace with the new Android Architecture Components recently. Essentially, I have a list of items in my ViewModel that are observed by my Fragment, using LiveData. When the ViewModel posts a new value for the data, the Fragment updates the adapter, passing in these new data elements and notifying the adapter that there have been changes.

    Unfortunately, when passing in the new data elements to the adapter, I failed to account for the fact that both the ViewModel and the Adapter would be pointing to the same object reference! Meaning that if I update the data and call postValue() from within the ViewModel, there's a very small window where the data could be updated and the adapter not yet notified!

    My fix was to instantiate a fresh copy of the elements when passed in to the adapter:

    mList = new ArrayList<>(passedList);

    With this super easy fix you can be ensured your adapter data will not change until right before your adapter is notified.

    This exception raised on API 19, 21 (but not new). In Kotlin coroutine I loaded data (in background thread) and in UI thread added and showed them:

    adapter.addItem(item)
    

    Adapter:

    var list: MutableList<Item> = mutableListOf()
    init {
        this.setHasStableIds(true)
    open fun addItem(item: Item) {
        list.add(item)
        notifyItemInserted(list.lastIndex)
    

    For some reason Android doesn't render quick enough or something else, so, I update a list in post method of the RecyclerView (add, remove, update events of items):

    view.recycler_view.post { adapter.addItem(item) }
    

    This exception is similar to "Cannot call this method in a scroll callback. Scroll callbacks mightbe run during a measure & layout pass where you cannot change theRecyclerView data. Any method call that might change the structureof the RecyclerView or the adapter contents should be postponed tothe next frame.": Recyclerview - cannot call this method in a scroll callback.

    I've just fixed the same issue. I had a RecyclerView.Adapter with setHasStableIds(true) set to avoid items blinking.

    I was using a duplicatable field in getItemId() (my model has no id field):

    override fun getItemId(position: Int): Long {
        // Error-prone due to possibly duplicate name.
        return contacts[position].name.hashCode().toLong()
    

    getItemId() should return a unique id for each item, so the solution was to do it:

    override fun getItemId(position: Int): Long {
        // Contact's phone is unique, so I use it instead.
        return contacts[position].phone.hashCode().toLong()
    

    this problem may happen when you try clearing your list, if you are going to clear your data list especially when you are using pull to refresh try to use a boolean flag, initialize it as false and inside OnRefresh method make it true, clear your dataList if flag is true just before adding the new data to it and after that make it false.

    your code might be like this

     private boolean pullToRefreshFlag = false ;
     private ArrayList<your object> dataList ;
     private Adapter adapter ;
     public class myClass extend Fragment implements SwipeRefreshLayout.OnRefreshListener{
     private void requestUpdateList() {
         if (pullToRefresh) {
            dataList.clear
            pullToRefreshFlag = false;
         dataList.addAll(your data);
         adapter.notifyDataSetChanged;
     @Override
     OnRefresh() {
     PullToRefreshFlag = true
     reqUpdateList() ; 
    

    I had a same issue previously. Finally found a workaround for that

    What i do is to notify adapter that item has removed and then notify adapter data set range changed

     public void setData(List<Data> dataList) {
          if (this.dataList.size() > 0) {
              notifyItemRangeRemoved(0, dataList.size());
              this.dataList.clear();
          this.dataList.addAll(dataList)
          notifyItemRangeChanged(0, dataList.size());
    

    For fix this issue just call notifyDataSetChanged() with empty list before updating recycle view.

    For example

    //Method for refresh recycle view
        if (!hcpArray.isEmpty())
    

    hcpArray.clear();//The list for update recycle view

    adapter.notifyDataSetChanged();
                    @Milha I didn't get any other solution to fix the crash issue. But the above solution is worked for me.   If it is not a solution the tell me the proper fix.
    – EKN
                    Aug 10, 2017 at 4:39
                    It depends. You can try using DiffUtil — a general-purpose tool for updating RecyclerView contents.
    – Miha_x64
                    Aug 10, 2017 at 13:58