web-dev-qa-db-ja.com

RecyclerView:キャッシュ/リサイクルされたビューをクリアする方法は?

RecyclerViewを使用して、リストレイアウトでアイテムのリストを表示します。リストレイアウトからグリッドレイアウトに切り替え、グリッドレイアウトではすべてのデータのサブセットのみを表示します。このスイッチは、リストレイアウトが表示される場合とは異なるレイアウトXMLを使用します。

スクロールすると、リサイクル(キャッシュ?)リストレイアウトビューがグリッドに表示され、適切なグリッドレイアウトビューアイテムと混合されることを除いて、これはすべて正常に機能します。つまり、RecyclerViewの各アイテムのレイアウトに_layout_grid.xml_を使用する代わりに、_layout_list.xml_レイアウトを使用してアイテムを取得しますが、グリッド形式です。

これにより、LayoutManagerが正しく機能し、リストからグリッドレイアウトに切り替えられたことがわかります。ただし、すべてのアイテムビューアイテムがグリッドxmlレイアウトを使用して再作成されるわけではなく、リサイクルされたリストレイアウトビューが使用されます。

RecyclerView.removeAllViews()RecyclerView.removeAllViewInLayout()RecyclerView.swapAdapter()(アダプターのリロードを強制する)を試してみましたが、すべて役に立ちませんでした。

更新:

リスト内で2つの位置を下にスクロールし、リストからグリッドに切り替えると、最初の2つの位置はonCreateViewHolder()を通過せず、onBindViewHolder()に直接移動するため、グリッドレイアウトxmlの使用を強制されません。代わりに、最初の2つの位置項目はリサイクルされ(私が思うに)、リストレイアウト形式で表示されます。

23
mraviator

ああ、わかってるよ。両方のレイアウトを使用しますか?リスト/グリッド要素(id/position)のビュータイプを返すメソッドがあります。このメソッドを正しく実装し、アダプターが新しいビューの正しいレイアウトをリサイクルできるようにします。私の言うことを理解していますか? :)

6
Mann

つかいます

recyclerView.getRecycledViewPool().clear();
22
Oleg Kovalyk

同じ問題がありました。 Mannによって提案された解決策はうまく機能します。他のオプションは、RecyclerViewのRecycledViewPoolを新しいインスタンスに設定することです。それは私にも有効です。

recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());

しかし、getItemViewType()をオーバーライドする方がよりクリーンなソリューションだと思います。

8
goflo

受け入れられた答えがあなたの場合に正しいものであるように聞こえますが、異なるviewTypeを返すことはおそらくあなたがする必要があったものです。

誰かがキャッシュされたビューホルダーをクリアする方法を見つける必要があり、このスレッドになった場合、ここで私が働いたことがわかりました。

setLayoutManager(null)およびsetAdapter(null)を呼び出す必要があります。アダプタを保持したい場合は、adapter = getAdapter(); setAdapter(null); setAdapter(adapter);のようなことができます

6
cottonBallPaws

ここで重要なのは、getItemViewType(int position)をオーバーライドして設定し、その位置で処理しているビュータイプ(リストまたはグリッド)を確認し、onbindViewHolder()。以下のviewFormatは、ユーザーがメニューボタンをタップして形式を変更するときにリストまたはグリッドに設定するintです。

@Override
    public int getItemViewType(int position) {
        if (listData.size() == 0) {
            return EMPTY_VIEW;
        } else if (viewFormat == Constants.LIST_FORMATTED) {
            return Constants.LIST_FORMATTED;
        } else if (viewFormat == Constants.GRID_CONDITION) {
            return Constants.GRID_CONDITION;
        }
        return super.getItemViewType(position);
    }

元の投稿にコメントを投稿したユーザーがこれを認識しましたが、残念ながらそれらのコメントは編集されました。そのユーザーに正しい方向を示してくれたことに感謝します。

4
mraviator

Recyclerviewには、ビューキャッシュとリサイクルビュープール(ビューホルダープール)があります。

キャッシュはビュー(データが入力されたビュー)です。 LayoutManagerがrecyclerviewにビューが表示されなくなり、必要であると伝えると、recyclerviewはそのビューが特定の位置に対してまだ有効かどうかをチェックし、有効であればキャッシュに追加されます。そのままキャッシュから。

次に、再生ビュープールとは何ですか?ビューがキャッシュから削除されるか、有効なビューではなくなった場合、それらのビューに関連するデータは消去され、ビューホルダーオブジェクトのみがプールに保持されます。 itemTypeに応じて、プールは異なるアイテムタイプのビューホルダーを持つことができます。

今、あなたの場合、あなたは完全に異なるビューを表示したいので、あなたのビューはその特定の位置に対して有効ではありません。そのため、アダプターはすべてのビューが無効であることをrecyclerviewに通知する必要があります。唯一の方法は、すべてのアイテムにnotifyDataSetChangedを使用することです。 Recyclerviewは、キャッシュからビューを削除し、それらをリサイラービュープールに追加します。したがって、LMがビューを要求すると、リサイクルされたビュー(itemTypeによる)または新しく作成されたビューが返され、アダプターはこれらのビューにデータをバインドします。

0
Virat18
final int targetCacheSize = 2;
    recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
    recyclerView.getRecycledViewPool().clear();
    recyclerView.setItemViewCacheSize(targetCacheSize);
0
李海标

簡単にこれを実行してください!!

adapter.notifyItemRangeRemoved(0,adapter.getItemCount());

  adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
                   for (int i = 0; i < array.length(); i++) {
                        JSONObject object = array.getJSONObject(i);
                         ////
                        data_List.add(data);
                    }
0
Shahjad S