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
私は(おそらく)関連する問題を抱えていました - RecyclerViewでアクティビティの新しいインスタンスを入力すると、もっと小さなアダプタでこのクラッシュを引き起こしていました。
RecyclerView.dispatchLayout()
はmRecycler.clearOldPositions()
を呼び出す前にスクラップから項目を引き出そうとすることができます。その結果、アダプタサイズより高い位置にあるアイテムを共通プールから引き出すことになりました。
幸い、これはPredictiveAnimations
が有効な場合にのみ行われるので、私の解決策はGridLayoutManager
をサブクラス化し(LinearLayoutManager
にも同じ問題と 'fix'があります)、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);
}
}
私の場合(データ構造からデータを削除/挿入する)、私はリサイクルプールをクリアしてからデータセットが変更されたことを通知する必要がありました!
mRecyclerView.getRecycledViewPool().clear(); mAdapter.notifyDataSetChanged();
この場合はnotifyItem...
の代わりにnotifyDataSetChanged()
を使用してください。
私はmRecycler.setAdapter(itemsAdapter)
を使ってアダプタにすべての項目を追加した後までmRecycler.addAll(items)
を遅らせることでこれを解決しました、そしてそれはうまくいきました。私が最初にそれをしたのは、私が見たライブラリのコードから "間違った順序"でそれらの行を見たのがわかりませんでした。そう?これが正当な答えであるかどうかさえわからない
私は似たような問題を抱えていましたが、まったく同じというわけではありません。私の場合は1点で、recyclerviewに渡された配列をクリアしていました
mObjects.clear();
リサイクルデータをすぐにクリアしたくないため、notifyDataSetChangedを呼び出さないでください。 AsyncTaskでmObjects配列を再入力していました。
私は同じ問題を抱えています。それは私が速くスクロールしてAPIを呼び出してデータを更新していたときに起こりました。
mRecyclerView.stopScroll();
それが動作します。
このエラーは、ユーザーがアイテムホルダーの位置を変更するときにスクロールすると、アダプター内のリストがクリアされ、リストとアイテムの間の参照が失われ、次の "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 さん、ありがとうございます。
つかいます
notifyDataSetChanged()
代わりに
notifyItemRangeInserted(0, YourArrayList.size())
この場合。
この問題を解決するには、リサイクルビューを更新する前に、空のリストを指定してnotifyDataSetChanged()を呼び出すだけです。
例えば
//Method for refresh recycle view
if (!hcpArray.isEmpty())
hcpArray.clear(); //更新リサイクルビューのリスト
adapter.notifyDataSetChanged();
RecyclerViewでも同じ問題がありましたので、リストがクリアされた直後にデータセットの変更についてアダプタに通知しました。
mList.clear();
mAdapter.notifyDataSetChanged();
mList.addAll(newData);
mAdapter.notifyDataSetChanged();
参照ではなくitems配列のコピーを使用するようにAdapter
の実装を変更した後、私の問題は解決しました。 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);
}
私の場合は、アイテムを更新し、非UIスレッドでnotifyDataSetChanged
を呼び出していました。ほとんどの場合うまくいきましたが、多くの変更がすぐに起こるとクラッシュしました。私がしたとき、代わりに、基本的に
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
changeData();
notifyDataSetChanged();
}
});
それからそれはクラッシュしなくなりました。
RecyclerView
のデータをバックグラウンドThread
で変更しています。私はOPと同じException
を手に入れました。データを変更した後にこれを追加しました。
myRecyclerView.post(new Runnable() {
@Override
public void run() {
myRecyclerAdapter.notifyDataSetChanged();
}
});
それが役に立てば幸い
あなたは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.
になるので、pull-refreshの間にスクロールすると、これが起こることを発見しました。
swipeContainer.setRefreshing(false);
//TODO : This is very crucial , You need to clear before populating new items
listings.clear();
そうすれば、矛盾が生じることはありません。
私は同じ状況に直面しました。コレクションをクリアする前にコードを追加して解決しました。
mRecyclerView.getRecycledViewPool().clear();
この問題は、リストをクリアしようとしたときに発生する可能性があります。特に、pullを使用してリフレッシュするときにデータリストをクリアする場合は、ブール値フラグを使用してください。 flagが新しいデータを追加する直前に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() ;
}
}
私は最近、新しいAndroid Architecture Componentsでこの厄介なスタックトレースを見つけました。基本的に、LiveDataを使用して、自分のFragmentで観察されるViewModel内の項目のリストがあります。 ViewModelがデータに新しい値を送信すると、Fragmentはアダプタを更新し、これらの新しいデータ要素を渡して、アダプタに変更があったことを通知します。
残念ながら、新しいデータ要素をアダプタに渡すときに、ViewModelとアダプタの両方が同じオブジェクト参照を指しているという事実を説明できませんでした。つまり、ViewModel内でデータを更新してpostValue()
を呼び出すと、データが更新される可能性がある非常に小さなウィンドウがあり、アダプタにはまだ通知されていません。
私の解決策は、アダプタに渡されたときに要素の新しいコピーをインスタンス化することでした:
mList = new ArrayList<>(passedList);
この非常に簡単な修正により、アダプタに通知される直前までアダプタデータが変更されないようにすることができます。
私は似たような問題に遭遇し、そしてちょうどそれを考え出しました。テストケース用にいくつかの例をハードコーディングしましたが、それらがそれぞれ一意のIDを返すことを保証するものではなかったため、以下のクラッシュが発生しました。 IDを修正することで問題が解決しました。これが他の人に役立つことを願っています!
私の場合はsetHasStableIds(true);
で行を削除しました
また、アダプタを同時に複数回設定することにも関連する可能性があります。同時に5〜6回起動されるコールバックメソッドがあり、そのコールバックでアダプタを設定していたため、RecycledViewPoolがこれらすべてのデータを同時に処理できませんでした。それは大きなチャンスですが、とにかくそれをチェックした方がいいでしょう。
通知する前に、レイアウトマネージャのすべてのビューを削除するだけです。好きです:
myLayoutmanager.removeAllViews();
これはかなり厄介なバグです。
私のアイテムのクリックを処理するために、私は この質問 にある解決策と同様のRecyclerView.OnItemTouchListener
の実装を使いました。
RecyclerView
のデータソースを何度も更新して項目をクリックした後、このIndexOutOfBoundsException
は私のアプリケーションをクラッシュさせるでしょう。アイテムがクリックされると、RecyclerView
は内部的に正しい基礎となるビューを探し、その位置を返します。ソースコードを調べてみると、Tasks
とThreads
がスケジュールされていることがわかりました。話を簡単にすると、基本的には2つのデータソースが混在し、同期されていないという、まったく違法な状態です。
これに基づいて、私は私のRecyclerView.OnItemTouchListener
の実装を削除し、ViewHolder
のAdapter
をクリックしました。
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
}
});
}
これは最善の解決策ではないかもしれませんが、今のところクラッシュフリーです。うまくいけば、これで時間が節約できます:)。
add_location.removeAllViews();
for (int i=0;i<arrayList.size();i++)
{
add_location.addView(new HolderDropoff(AddDropOffActivtity.this,add_location,arrayList,AddDropOffActivtity.this,this));
}
add_location.getAdapter().notifyDataSetChanged();
Lintが矛盾についてアドバイスしてくれました。(onBindViewHolder())を書きました。
pholder.mRlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doStuff(position);
}
});
これは次のように置き換えられます。
pholder.mRlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doStuff(pholder.getAdapterPosition());
}
});
あなたのコードで両方のコードを実行してから、完全な説明のためにLintを実行してください。
私も一度エラーを得ました:
原因:古い削除されたviewHoldersを同時に取得しようとしているときに、AsyncタスクからRecycler Viewを更新しようとしました。
コード:ボタンを押すだけでデータが生成されます。ロジックは以下の通りです。
問題:データを生成する前に速くスクロールするときはいつでも
矛盾が検出されました。無効なビューホルダアダプタpositionViewHolder Java.lang.IndexOutOfBoundsException:矛盾が検出されました。無効な商品位置20(オフセット:2)、状態:3
解決策:私のデータを生成する前にRecyclerViewをクリアする代わりに、私は代わりにそれを残して、次に示すように新しいデータと交換します;
@Override
protected void onPostExecute(List<Objects> o) {
super.onPostExecute(o);
recyclerViewAdapter.setList(o);
mProgressBar.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
}
私にとっては、このコード行を追加した後でうまくいきました。
mRecyclerView.setItemAnimator(null);
私が認識していなかったときに問題が発生しました。異なるスレッドで同時に2回呼び出しました。
notifyDataSetChanged
sqliteロード関数から1つ、関数呼び出し後から1つ
私はこの問題を解決し、新しいデータを取得するときに項目を一つずつ追加しました。アダプター内でこの機能を使用しています。
public void add(Data item) {
if(!params.contains(item){
params.add(item);
notifyItemInserted(getItemCount() - 1);
}
}
}
申し訳ありませんが完璧な解決策:特定のアイテムを削除しようとするときにnotifydatasetchange()を呼び出してそのアイテムをbindviewholderで取得し、そのアイテムを削除してから最後のリストに追加してください。項目。基本的にあなたが中心からアイテムを取り除こうとするとき、問題は来ます。最後のインデックスから項目を削除すると、それ以上リサイクルは行われず、追加者の数も重要ではなくなり(これはここで重要なクラッシュになります)、クラッシュは以下のコードスニペットで解決されます。
holder.itemLayout.setVisibility( View.GONE );//to hide temprory it show like you have removed item
Model current = list.get( position );
list.remove( current );
list.add( list.size(), current );//add agine to last index
if(position==list.size()-1){// remove from last index
list.remove( position );
}
私は以前に同じ問題を抱えていました。最後にそれに対する回避策を見つけました
アイテムが削除されたことをアダプタに通知し、アダプタデータセットの範囲が変更されたことを通知する
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());
}
私の場合は、バックグラウンドスレッドでアダプタの内容を変更しようとしましたが、メイン/ uiスレッドではnotify *を呼び出しました。
これは不可能です!notifyがメインスレッドに強制されるのは、同じコールスタック上であっても、recyclerviewがメインスレッド上でバッキングアダプタを編集することを望んでいるためです。
問題を解決するには、アダプタへのすべての操作とnotify ...呼び出しのすべてがui /メインスレッドで行われるようにします。
これは私のために働いた唯一の解決策であり、上記の解決策から多くを試してもいます。
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 - >このリストはアダプタで使用しているものです。
非常に遅い応答ですが、これは機能に関する誰かを助けるかもしれません。
OnStopまたはonPauseメソッドがリストをクリアしていないことを確認してください
私はその設定mRecycler.setLayoutFrozen(true)を見つけました。 swipeContainerのonRefreshメソッドで。
私のために問題を解決しました。
swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
orderlistRecycler.setLayoutFrozen(true);
loadData(false);
}
});