RecyclerViewデータのリフレッシュについて
3675 ワード
RecyclerViewを使用してデータの削除または追加を行うと、次のような異常が発生することがあります.
では、この異常はどのように発生し、どのように解決されるのでしょうか.
RecyclerViewでは、4つの方法でデータをリフレッシュします.1.notifyDataSetChanged();これはListViewの使用方法で、RecyclerViewでも同様に適用されますが、これは公式に推奨されていません.RecyclerViewはListViewに対してローカルリフレッシュインタフェースを提供し、ローカルリフレッシュはアニメーション効果があるためです.2.notifyItemRangeRemoved(); 3.notifyItemRangeInserted(); 4.notifyItemRangeChanged();
データをリフレッシュする後の3つの方法は推奨されますが、うまく使えないとさっきの文章からの異常が発生します.この異常発生の原因を分析する.
以前の個人開発で発生した問題を見てみましょう.
以上のコードでは、insertDataに空のデータがある場合に異常が発生し、空のデータがある場合は、後のnotifyItemRangeInsertedの開始位置と増加したitem数がmDatasの中のものと一致せず、mDatasはadapter内部データとなり、insertDataは外部データとなり、リアルタイムでデータの一致性を保つべきである.
もう一つの問題は、RecyclerViewデータのリフレッシュ操作を「原子」操作に分解し、「原子」操作を3つにし、削除、追加、修正することです.例を挙げて説明します.
上記の操作では、まずデータを削除しましたが、RecyclerViewをリフレッシュしていません.その後、データを追加しました.この場合、RecyclerViewをリフレッシュします.この場合、問題が発生します.このプロセスを2つのステップに分割します.
そこで、RecyclerViewのローカルリフレッシュ機能を使用すると、adapterの内部データセットが変更されるたびに、データの一貫性を保つために、データリフレッシュをアクティブに呼び出します.
参考記事:http://www.jianshu.com/p/2eca433869e9
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{431a7450 position=1 id=-1, oldPos=-1, pLpos:-1 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4251)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4382)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2900)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3071)
では、この異常はどのように発生し、どのように解決されるのでしょうか.
RecyclerViewでは、4つの方法でデータをリフレッシュします.1.notifyDataSetChanged();これはListViewの使用方法で、RecyclerViewでも同様に適用されますが、これは公式に推奨されていません.RecyclerViewはListViewに対してローカルリフレッシュインタフェースを提供し、ローカルリフレッシュはアニメーション効果があるためです.2.notifyItemRangeRemoved(); 3.notifyItemRangeInserted(); 4.notifyItemRangeChanged();
データをリフレッシュする後の3つの方法は推奨されますが、うまく使えないとさっきの文章からの異常が発生します.この異常発生の原因を分析する.
以前の個人開発で発生した問題を見てみましょう.
/**
*
*/
public void insertData(List insertedData) {
if (insertedData == null) {
Log.e(TAG, "insertData(list) list is null");
return;
}
for (T data : insertedData){
if (data!=null){
mDatas.add(data);
}
}
notifyItemRangeInserted(mDatas.size() - insertedData.size(), insertedData.size());
}
以上のコードでは、insertDataに空のデータがある場合に異常が発生し、空のデータがある場合は、後のnotifyItemRangeInsertedの開始位置と増加したitem数がmDatasの中のものと一致せず、mDatasはadapter内部データとなり、insertDataは外部データとなり、リアルタイムでデータの一致性を保つべきである.
:
/**
*
*/
public void insertData(List insertedData) {
if (insertedData == null) {
Log.e(TAG, "insertData(list) list is null");
return;
}
int index = 0;
for (T data : insertedData) {
if (data != null) {
mDatas.add(data);
index++;
}
}
notifyItemRangeInserted(mDatas.size() - index, index);
}
もう一つの問題は、RecyclerViewデータのリフレッシュ操作を「原子」操作に分解し、「原子」操作を3つにし、削除、追加、修正することです.例を挙げて説明します.
public void notifyData(List poiItemList) {
if (poiItemList != null ) {
mPoiItems.clear();
mPoiItems.addAll(poiItemList);
notifyItemRangeChanged(0, poiItemList.size());
}
}
上記の操作では、まずデータを削除しましたが、RecyclerViewをリフレッシュしていません.その後、データを追加しました.この場合、RecyclerViewをリフレッシュします.この場合、問題が発生します.このプロセスを2つのステップに分割します.
public void notifyData(List poiItemList) {
if (poiItemList != null) {
int previousSize = mPoiItems.size();
mPoiItems.clear();
notifyItemRangeRemoved(0, previousSize);
mPoiItems.addAll(poiItemList);
notifyItemRangeInserted(0, poiItemList.size());
}
}
そこで、RecyclerViewのローカルリフレッシュ機能を使用すると、adapterの内部データセットが変更されるたびに、データの一貫性を保つために、データリフレッシュをアクティブに呼び出します.
参考記事:http://www.jianshu.com/p/2eca433869e9