RecyclerView:不整合が検出されました。アイテムの位置が無効です


271

QAがバグを検出しました。Androidデバイス(Droid Turbo)を回転させると、次のRecyclerView関連のクラッシュが発生しました。

java.lang.IndexOutOfBoundsException:不整合が検出されました。無効なアイテム位置2(オフセット:2)。状態:3

私には、RecyclerView内の内部エラーのように見えます。これがコードによって直接引き起こされているとは考えられないので...

誰かがこの問題に遭遇しましたか?

解決策は何でしょうか?

残忍な回避策としては、例外が発生したときに例外をキャッチし、RecyclverViewインスタンスを最初から作成し直して、破損した状態のままになるのを防ぐことができます。

しかし、可能であれば、問題をマスキングする代わりに、問題をよりよく理解したいと思います(そして、おそらくその原因を修正します)。

このバグは再現が簡単ではありませんが、発生すると致命的です。

完全なスタックトレース:

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

2
質問:再現はどの程度一貫していますか?私はこれがここここのグーグルのコードのエラーであることを知っています。しかし、これは回避できます。それで、これはすべての回転で起こりますか?
VicVu

こんにちは。まれにしか発生しませんが、発生するとアプリにとって致命的です。
KarolDepka

バグへのリンクをありがとう。最初のものは2番目のものよりも関連があるようです。
KarolDepka

1
ええ、あなたの最善の策は、ローテーション中にリストビューへの変更を許可しないことです。
VicVu

1
簡単に再現できる場合は、「notify *」のすべての呼び出しの前に「getItemCount」の値を出力することをお勧めします。アイテム数が想定と一致しない場合があります。
Rich Ehmer 2015年

回答:


209

(おそらく)関連する問題がありました-RecyclerViewを使用してアクティビティの新しいインスタンスを入力しましたが、小さいアダプターを使用すると、このクラッシュが発生しました。

RecyclerView.dispatchLayout()を呼び出す前にスクラップからアイテムをプルしようとすることができmRecycler.clearOldPositions()ます。その結果、アダプターサイズよりも高い位置にある共通プールからアイテムが取得されていました。

幸いにも、これPredictiveAnimationsが有効になっている場合にのみこれを行うので、私の解決策はサブクラス化しGridLayoutManagerLinearLayoutManager同じ問題と「修正」があり)、オーバーライドsupportsPredictiveItemAnimations()して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);
    }
}

4
これは私にとってはうまくいき、予測アニメーションを無効にしても、アニメーションがすべて失われることはありません。ブラボー。
Robert Liberatore

8
ありがとうございます!LinearLayoutManagerと即座に連携し、おそらく数日を節約できました。
levavare

8
どうもありがとう。このソリューションは、LinearLayoutManagerで動作します。
Pruthviraj 2016年

8
私はそれがウェブ上最悪の文書化の問題の一つだが、それはこの問題のdevの出会いがたくさんいるようだ...私だけの不思議が...この男は、我々は彼の貴重な助けに敬意を表して銅像を建てるに値すると思いますどのようにあなたがそれを見つけた可能性がPredictiveAnimationsがfalseの場合はスキップされます、@ KasHunt?スタックトレースが非常に不明瞭だからです...
PAD

4
誰もが知っている、このハックなしでそれを修正する方法は?notifyDatasetChangedがDiffUtilを支持して削除されたため
Anton Shkurenko 2018年

83

私の場合(データ構造のデータを削除/挿入)、リサイクルプールをクリアしてから、データセットの変更を通知する必要がありました。

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


6
私は通常これを言うことはありませんが、どうもありがとうございます。私は、リスト上のアイテムの束をすばやく順番に移動しているときに散発的に発生するこのクラッシュを修正するために、すべてを試しました。この問題を解決するために、文字通りおそらく1週間を費やしてきました。私は2、3か月離れて、脳に別の方法でアプローチする機会を与えようと試み、その後、これを最初のGoogleの試みで見つけました。お大事に!
Chantell Osejo 2016

たくさんのクッキーを手に入れさせてください。あなたはそれらすべてに値するのです。ありがとうございました。
antonis_st 2017年

なぜこれをしなければならないのですか?
dabluck

9
これは、非常に重い操作であり、ビューをリサイクルする目的をある程度無効にします。
gjsalot 2017年

@gjsalotこれを使用すると、問題が発生する可能性がありますか?
Sreekanth Karumanaghat

38

この場合はnotifyDataSetChanged()代わりnotifyItem...に使用してください。


5
場合によっては、これが適切な方法です。すべてのアイテムを交換した状況がありましたが、アダプターに正直ではなく、いくつかの新しいアイテム(notifyItemRangeInserted)を挿入したことだけを通知しました。次に、アダプターは、実際にあったよりも多くの項目があることを期待していました。アダプターの通知メソッドのいずれかを使用する場合は、notifyDataSetChanged(notifyItemRangeRemoved / Inserted / Updatedなど)が必要な場合、呼び出し元はアダプターに変更内容を正確に通知する責任があります。そうしないと、この「不整合な状態」になる可能性があります。
JHH

19
これはまったく解決策ではありません。
Miha_x64

これは進むべき道ではありません。これが機能する場合、notifyItem...すべてのアイテムを再レンダリングするのではなく、範囲を台無しにして修正すると機能し始めます。
ランジャン2018

12

私はmRecycler.setAdapter(itemsAdapter)すべてのアイテムをアダプターに追加した後までそれを遅らせることでこれを解決しmRecycler.addAll(items)、それはうまくいきました。なぜ私が最初にそれをしたのかわからない、それは私が調べて「間違った順序」でそれらの行を見たライブラリのコードからだった、それはそれがそれであるとかなり確信している。そう?これが有効な答えかどうかわからない


私はこれが解決策だと思いますが、アダプタを遅らせれば問題ないと思いました...今、UIスレッドでアダプタを設定し、それにアイテムを追加するとポップアップします。
EngineSense 2016

18
swapAdapter(adapter, true)代わりに使用しましたがsetAdapter(adapter)、役に立ちました。
フランジラヤン

11

同様の問題がありましたが、まったく同じではありませんでした。私の場合、ある時点で、recyclerviewに渡された配列をクリアしていました

mObjects.clear();

また、recyclerviewでビューをすぐにクリアしたくないので、notifyDataSetChangedを呼び出さないでください。AsyncTaskでmObjects配列を再入力しました。


9

recyclerViewでも同じ問題が発生したので、リストがクリアされた直後にデータセットの変更についてアダプターに通知しました。

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

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

1
この単純な間違いで私は多くの時間を失いました。どうもありがとう!
leb1755

7

同じ問題があります。高速でスクロールしてAPIを呼び出し、データを更新しているときに発生しました。クラッシュを防ぐためにあらゆることを試した後、解決策を見つけました。

mRecyclerView.stopScroll();

それが動作します。


これは修正ではなく回避策です。スクロールを強制的に停止します。悪いUX
aNdRO博士18年

1
@ Dr.aNdRO:アダプターは位置を設定する必要があり、recylerviewをスクロールし続けると、アダプターはクラッシュの原因であるデータを設定できません。悪いUXではありません
Anand Savjani

1
理にかなっています。データの更新が行われるため、スクロールの停止は悪いuxではありません。
2018

6

RecyclerViewバックグラウンドでのデータを変更していますThreadExceptionOP と同じになりました。私はデータを変更した後にこれを追加しました:

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

それが役に立てば幸い


ありがとう!これは、Android開発の観点から理解できる唯一の答えです。
user347187

私もの助けを借りて解決しましたがview.recycler_view.post、使用しましたnotifyItemInserted。私の場合、それはすでにUIスレッドです。
CoolMind

6

このエラーは、ユーザーがスクロールしてアイテムホルダーの位置を変更したときにアダプターのリストがクリアされ、UIのリストとアイテム間の参照が失われた場合に発生し、次の"notifyDataSetChanged"リクエストでエラーが発生し ます。

修正:

リストの更新方法を確認します。あなたが何かをした場合

mainList.clear();
...
mainList.add() or mainList.addAll()
...
notifyDataSetChanged();

===> Error occur

直し方。バッファ処理用の新しいリストオブジェクトを作成し、その後メインリストに再度割り当てます

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

この素晴らしい助けをしてくれたNhan Caoに感謝します:)


4

Adapter参照の代わりにitems配列のコピーを使用するように実装を変更した後、私の問題はなくなりました。setItems()この方法は、我々はに表示する新しいアイテムを持っているたびに呼び出されますRecyclerView

の代わりに:

private class MyAdapter extends RecyclerView.Adapter<ItemHolder> {
     private List<MyItem> mItems;  

    (....)

    void setItems(List<MyItem> items) {
        mItems = items;
    }
}

やった:

void setItems(List<MyItem> items) {
    mItems = new ArrayList<>(items);
}

これで問題は解決しますが、元のメモリの2倍になるのではないでしょうか。
Sreekanth Karumanaghat

@ MiguelA.Gabrielこれはパフォーマンスに影響しますか?たとえば、私の場合、recylerviewの配列を頻繁に更新しているため、現在これsuggestionsRecyclerView.swapAdapter(new CandidatesAdapter(mSuggestions), true); を実行しています。これは私のコンストラクタです public CandidatesAdapter(List<String> suggestionsList) { this.suggestionsList = new ArrayList<>(suggestionsList); }
Mateen Chaudhry

@ mateen-chaudhryたぶんそうなるでしょう。あなたはあなたのケースでそれをテストして決定するか、提案されたソリューションの別のものを使用してみる必要があります。言ったように、これは回避策にすぎず、私の場合は私にとってはうまくいきます。
ミゲルA.ガブリエル

3

私も同じ状況に直面しています。また、コレクションをクリアする前にコードを追加することで解決しました。

mRecyclerView.getRecycledViewPool().clear();


3

私の場合、アイテムを更新notifyDataSetChangedして非UIスレッドで呼び出していました。ほとんどの場合は機能しましたが、多くの変更が迅速に行われると、クラッシュしました。代わりに、基本的に

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

その後、クラッシュを停止しました。


3

OnPostExecute()実行中にリストをクリアするだけで済みます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

            }
        });

私はあなたが中にスクロールしたときにこれが起こることを発見したリフレッシュにプル私は前にリストをクリアしているので、async taskその結果得られます、 java.lang.IndexOutOfBoundsException: Inconsistency detected.

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

そうすれば、一貫性が失われることはありません


2

また、アダプターを同時に複数回設定することにも関連しています。同時に5〜6回トリガーされるコールバックメソッドがあり、そのコールバックにアダプターを設定して、RecycledViewPoolがこれらのデータすべてを同時に処理できなかった。大きなチャンスですが、とにかくチェックしてみてください。


1
はい同じ問題..しかし、解決策?理由だけを教えてください。修正方法は?
Ranjith Kumar

@RanjithKumar、上記の問題を解決するための方法を親切に共有してください。mRecyclerView.getRecycledViewPool()。clear();を使用して解決しました。notifyDataSetChangedの前、およびアダプターの更新機能に関連する同期ブロックの使用
Attiq ur Rehman

私のコードを見てください。私の問題はあなたの問題と同じだと思います。stackoverflow.com
questions / 50213362 /

2

使用する

notifyDataSetChanged()

代わりに

notifyItemRangeInserted(0, YourArrayList.size())

この場合。


1
しかし、これはパフォーマンスに適していませんね?notifyItemRangeInsertedの方が優れています。問題はここにはありません
Derekyy

2

この問題を修正するには、リサイクルビューを更新する前に、リストを空にしてnotifyDataSetChanged()を呼び出します。

例えば

//Method for refresh recycle view

    if (!hcpArray.isEmpty())

hcpArray.clear(); //更新リサイクルビューのリスト

adapter.notifyDataSetChanged();

2
解決策ではありません。
Miha_x64

@Milhaクラッシュの問題を解決する他の解決策はありませんでした。しかし、上記の解決策は私のために働いています。それが解決策でない場合は、適切な修正を教えてください。
EKN、2017

場合によります。DiffUtil — RecyclerViewコンテンツを更新するための汎用ツールを使用してみてください。
Miha_x64 2017

2

私の場合、私はちょうど行を削除しました setHasStableIds(true);


しかし、HasStableIds(true)はRvのパフォーマンスを向上させます。代替ソリューションはありますか?
Sreekanth Karumanaghat

実際にはさまざまな理由が考えられるため、根本的な原因に基づいてこの問題の解決策が異なる可能性があります。
Sreekanth Karumanaghat

2

私の場合、バックグラウンドスレッドでアダプターの内容変更しようとしましたが、メイン/ UIスレッドでnotify *を呼び出しました。

それは不可能です!通知がメインスレッドに強制される理由は、recyclerviewが同じ呼び出しスタック上であっても、メインスレッドでバッキングアダプターを編集することを求めているためです。

この問題を解決するには、アダプタに対するすべての操作とすべての通知...呼び出しがui / mainスレッドで行われるようにしてください。


2
アダプターのリストに項目を追加するには、バックグラウンドスレッドで実行し、postexecuteでnotifyを呼び出す必要があります。UIスレッドにデータを追加すると、多くのデータを追加すると、アプリが数ミリ秒または数秒間フリーズします
dione llorera

@dionelloreraと合意した場合、「アダプタの内容の変更」は、プリミティブ値、オブジェクトのプロパティ、オブジェクト自体のいずれであっても、データを直接変更することを明確に意味することを明確にする必要があります
OzzyTheGiant

2

最近、新しいAndroidアーキテクチャコンポーネントでこの厄介なスタックトレースに遭遇しました。基本的に、ViewDataには、LiveDataを使用してFragmentによって監視される項目のリストがあります。ViewModelがデータの新しい値をポストすると、フラグメントはアダプタを更新し、これらの新しいデータ要素を渡して、変更があったことをアダプタに通知します。

残念ながら、新しいデータ要素をアダプターに渡すと、ViewModelとアダプターの両方が同じオブジェクト参照を指すという事実を説明できませんでした。つまり、データを更新しpostValue()てViewModel内から呼び出した場合、データを更新できる非常に小さなウィンドウがあり、アダプターにはまだ通知されていません。

私の修正は、アダプターに渡されたときに要素の新しいコピーをインスタンス化することでした:

mList = new ArrayList<>(passedList);

この非常に簡単な修正により、アダプターに通知される直前までアダプターデータが変更されないことが保証されます。


2

これは、上記の解決策の多くを試しても私にとってはうまくいった唯一の解決策です。

1.)受精

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

2.)このメソッドをアダプターに書き込みます

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

stockListModels->このリストは、アダプタで使用しているものです。


2

私にとっては、次のコード行を追加した後に機能しました:

mRecyclerView.setItemAnimator(null);

2
これはほとんどの場合の修正ではありません。アニメーションが必要な場合は、アダプターコードを書き直して、変更の通知でエラーを見つけてください
Dragos Rachieru

実際にアダプターを使用しているため、フローを制御できず、windowActivityTransitionsを有効にしたスタイルでこの問題の原因となっているおかげで、一日を節約できました。
Arul Mani

1

この問題は、リストをクリアしようとしたときに発生する可能性があります。特に、プルリフレッシュを使用してブールフラグを使用している場合にデータリストをクリアする場合は、ブールフラグを使用して初期化し、OnRefreshメソッド内でtrueにして、dataListをクリアします。新しいデータを追加する直前にフラグがtrueで、その後falseにする場合。

あなたのコードはこのようになるかもしれません

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

}

1

以前に同じ問題がありました。最後にそのための回避策を見つけました

アイテムが削除されたことをアダプターに通知してから、アダプターデータセットの範囲が変更されたことを通知する

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

 }

1

私は同様の問題に遭遇し、それを理解しました。テストケースのいくつかの例をハードコーディングしましたが、それぞれが一意のIDを返すことを確認していなかったため、以下のクラッシュが発生しました。IDを修正することで問題が解決しました。これが他の誰かの役に立つことを願っています!


1

私も一度エラーが発生しました:

原因:古い非同期のviewHoldersを取得しようとしながら、非同期タスクからリサイクラービューを更新しようとしました。

コード:次のように私は、ボタンを押すだけで、論理データを生成します

  1. ごみ箱ビューの最後のアイテムをクリアする
  2. 非同期タスクを呼び出してデータを生成する
  3. OnPostExecute RecyclerビューとNotifyDataSetChangedを更新します

問題:データを生成する前に高速でスクロールするたびに

不整合が検出されました。無効なビューホルダーアダプタのpositionViewHolder java.lang.IndexOutOfBoundsException:不整合が検出されました。無効なアイテム位置20(オフセット:2)。状態:3

解決策:データを生成する前にRecyclerViewをクリアする代わりに、そのままにして、次に示すように、NotifyDatasetChangedを呼び出す新しいデータで置き換えます。

       @Override
        protected void onPostExecute(List<Objects> o) {
            super.onPostExecute(o);
            recyclerViewAdapter.setList(o);
            mProgressBar.setVisibility(View.GONE);
            mRecyclerView.setVisibility(View.VISIBLE);
        }

私のコードを見てください。私の問題はあなたの問題に似ていると思います[リンク](stackoverflow.com/questions/50213362/…
Mateen Chaudhry

1

通知する前に、レイアウトマネージャのすべてのビューを削除してください。お気に入り:

myLayoutmanager.removeAllViews();

できます。スクロールの読み込みとタブの変更に問題がありました。
Warwicky

1

ListAdapter (androidx.recyclerview.widget.ListAdapter)呼び出すadapter.submitList(null)前に呼び出しを使用adapter.submitList(list)

adapter.submitList(null)
adapter.submitList(someDataList)

1

この例外はAPI 19、21で発生しました(新しいものではありません)。Kotlinコルーチンでは、データを(バックグラウンドスレッドで)ロードし、UIスレッドで追加して表示しました。

adapter.addItem(item)

アダプタ:

var list: MutableList<Item> = mutableListOf()

init {
    this.setHasStableIds(true)
}

open fun addItem(item: Item) {
    list.add(item)
    notifyItemInserted(list.lastIndex)
}

なんらかの理由でAndroidが十分に速くレンダリングされないなどの理由postで、RecyclerView(項目のイベントの追加、削除、更新)のメソッドでリストを更新します。

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

この例外は、「スクロールコールバックでこのメソッドを呼び出せません。RecyclerViewデータを変更できないメジャーとレイアウトパスの間にスクロールコールバックが実行される可能性があります。RecyclerViewの構造を変更する可能性のあるメソッド呼び出しやアダプターの内容は、次のフレーム。」:Recyclerview-スクロールコールバックでこのメソッドを呼び出すことはできません


0

mRecycler.setLayoutFrozen(true);を設定していることがわかりました。swipeContainerのonRefreshメソッド内。

私のために問題を解決しました。

swipeContainer.setOnRefreshListener(new   SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            orderlistRecycler.setLayoutFrozen(true);
            loadData(false);

        }
    });

0

これはかなり厄介なバグです。

私のアイテムのクリックを処理するために、私RecyclerView.OnItemTouchListenerはで見つかったソリューションと同様の実装を使用しましたこの質問で

RecyclerViewのデータソースを何度も更新してアイテムをクリックするとIndexOutOfBoundsException、アプリケーションがクラッシュします。アイテムがクリックされると、RecyclerView内部的に正しい基になるビューを探して、その位置を返します。ソースコードをチェックすると、いくつかあることがわかりましたTasksThreadsスケジュールされていました。話を簡潔に言うと、基本的には2つのデータソースが混在していて同期されておらず、全体が乱暴になっている、いくつかの違法な状態です。

これに基づいて、私はの実装を削除し、自分自身のRecyclerView.OnItemTouchListenerクリックをキャッチしました:ViewHolderAdapter

public void onBindViewHolder (final BaseContentView holder, final int position) {

    holder.itemView.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick (View view) {

        // do whatever you like here
      }
    });

}

これは最良の解決策ではないかもしれませんが、今のところクラッシュはありません。


onBindが呼び出されるたびに新しいオブジェクトを作成すると、多くのオブジェクトがガベージコレクションされ、ユーザーがフリーズする可能性があります。
デフィネラ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.