RecyclerView:キャッシュ(CachedViews)のサイズ

投稿日:  更新日:

RecyclerViewのリサイクル動作で使われるキャッシュは、サイズを大きくすれば多くのViewHolderが保持できます。その分、多くのメモリを消費します。

ViewHolderを多く保持できたとしても、サイクル動作で効率よく使われなければ、メモリの浪費です。

キャッシュのサイズはRecyclerViewの使われ方よって適切なサイズがあります。

そのため、RecyclerViewはキャッシュのサイズを変更できるようになっています。

スポンサーリンク

CachedViewsのデフォルトサイズ

CachedViewsのサイズはRecyclerView.RecyclerクラスのmViewCacheMaxフィールドが持っています。

    public final class Recycler {
        ...
        private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
        int mViewCacheMax = DEFAULT_CACHE_SIZE;
        ...
        static final int DEFAULT_CACHE_SIZE = 2;
        ...  

        public void setViewCacheSize(int viewCount) {
            mRequestedCacheMax = viewCount;
            updateViewCacheSize();
        }
		
        void updateViewCacheSize() {
            int extraCache = mLayout != null ? mLayout.mPrefetchMaxCountObserved : 0;
            mViewCacheMax = mRequestedCacheMax + extraCache;

            // first, try the views that can be recycled
            for (int i = mCachedViews.size() - 1;
                    i >= 0 && mCachedViews.size() > mViewCacheMax; i--) {
                recycleCachedViewAt(i);
            }
        }
		
		...
    }

mViewsCacheMaxはmRequestedCacheMax(初期値:2)とextraCacheの加算値です。

extraCacheの値はLayoutManager(抜粋中のmLayout)に依存します。列に並ぶViewHolderの数(orientation:VERTICALの時)がextraCacheに入ります。

よって、mViewsCacheMaxの値は表のようになります。

LayoutManager (spanCount)
LinearGrid(2)Grid(3)Grid(4)
mRequestedCacheMax2222
extraCache1234
mViewCacheMax3456
スポンサーリンク

CachedViewsのサイズ変更

mViewsCacheMaxはmRequestedCacheMax(初期値:2)とextraCacheの加算値であることを先に述べました。

このmRequestedCacheMaxはRecyclerView.Recycler#setViewCacheSize( )で変更できるようになっています。

    public final class Recycler {
        ...
        private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
        int mViewCacheMax = DEFAULT_CACHE_SIZE;
        ...
        static final int DEFAULT_CACHE_SIZE = 2;
        ...  

        public void setViewCacheSize(int viewCount) {
            mRequestedCacheMax = viewCount;
            updateViewCacheSize();
        }
		
        void updateViewCacheSize() {
            int extraCache = mLayout != null ? mLayout.mPrefetchMaxCountObserved : 0;
            mViewCacheMax = mRequestedCacheMax + extraCache;

            // first, try the views that can be recycled
            for (int i = mCachedViews.size() - 1;
                    i >= 0 && mCachedViews.size() > mViewCacheMax; i--) {
                recycleCachedViewAt(i);
            }
        }
		
		...
    }
    ...
    final Recycler mRecycler = new Recycler();
	...
    public void setItemViewCacheSize(int size) {
        mRecycler.setViewCacheSize(size);
    }
	...

これにより、CachedViewsのサイズを変更できます。

スポンサーリンク

CachedViewsの適切なサイズ

キャッシュのサイズを変更できることがわかったところで、最適なサイズを考察してみようと思います。

例えば、GridLayoutManagerでspanCount:3とし、スクロールした場合のリサイクル動作をあげます。

3列(extraCache:3)を同時にスクロールするのでキャッシュのサイズは5です。

000102
GridLayoutManager 3列をスクロール

... I/Adapter:     View Attached item = Item 9 [pos=9,type=0]
... I/Adapter:     View Attached item = Item A [pos=10,type=0]
... I/Adapter:     View Attached item = Item B [pos=11,type=0]
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 12
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 13
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 14
... I/Adapter:     View Detached item = Item 2 [pos=2,type=0]
... I/Adapter:     View Detached item = Item 1 [pos=1,type=0]
... I/Adapter:     View Detached item = Item 0 [pos=0,type=0]
... I/Adapter: View Recycled item = Item C [pos=12,type=0]
... I/Adapter:   Bind   ViewHolder!! position = 12

アイテム9/A/Bを表示した後に、次のアイテムC/D/Eをプリフェッチします。

GridLayoutManager 3列をスクロール

... I/Adapter:     View Attached item = Item 9 [pos=9,type=0]
... I/Adapter:     View Attached item = Item A [pos=10,type=0]
... I/Adapter:     View Attached item = Item B [pos=11,type=0]
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 12
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 13
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 14
... I/Adapter:     View Detached item = Item 2 [pos=2,type=0]
... I/Adapter:     View Detached item = Item 1 [pos=1,type=0]
... I/Adapter:     View Detached item = Item 0 [pos=0,type=0]
... I/Adapter: View Recycled item = Item C [pos=12,type=0]
... I/Adapter:   Bind   ViewHolder!! position = 12

スクロールが進むと、アイテム0/1/2が非表示なりCachedViewsに保持されます。しかし、空席が2つしかありません。そのためプリフェッチ中の1つが溢れてRecyclerPoolへ保持されます。

GridLayoutManager 3列をスクロール

... I/Adapter:     View Attached item = Item 9 [pos=9,type=0]
... I/Adapter:     View Attached item = Item A [pos=10,type=0]
... I/Adapter:     View Attached item = Item B [pos=11,type=0]
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 12
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 13
... I/Adapter: Create ViewHolder!! viewType = 0
... I/Adapter:   Bind   ViewHolder!! position = 14
... I/Adapter:     View Detached item = Item 2 [pos=2,type=0]
... I/Adapter:     View Detached item = Item 1 [pos=1,type=0]
... I/Adapter:     View Detached item = Item 0 [pos=0,type=0]
... I/Adapter: View Recycled item = Item C [pos=12,type=0]
... I/Adapter:   Bind   ViewHolder!! position = 12

アイテムCのプリフェッチが無くなってしまいました。ここで、再びアイテムCをプリフェッチする動作が発生します。

アイテムCが表示されるまでに、プリフェッチが2回行われる結果になります。この動作は無駄です。

無駄を無くすには、キャッシュサイズを6にして”プリフェッチ”と”非表示による保持”が共存できるようにします。

ですが …

最近のAndroid端末はとても高速なので、この程度の改善くらいでは体感できないことがほとんどです。

スポンサーリンク

関連記事:

RecyclerViewは子Viewを並べて表示するコンテナタイプ(ConstraintLayoutと同じ)のViewです。 複数のデータをスクリーン上に一覧表示したい時、例えば電話帳のような「氏名+住所+電話番号」の一覧を表示する場合などに最適です。 アプリを開発していると一覧表示したいデータが多いことに気付きます。 なのでRecyclerViewはとても重要で重宝するViewです。 しかし、思い通りの表示を行わせるためのテクニックが多すぎて、使いこなしが難しいです。 今まで調べたテクニックを忘れないように、整理して書き残そうと思います。 今回は基本の「RecyclerViewの実装」です。 ...
RecyclerViewでアイテムのクリックイベントを取得し、処理を実行する方法を紹介します。 ...
RecyclerViewはアイテムのレイアウトをアイテム毎に変更できます。その時に使う値がViewTypeです。 ViewTypeでアイテムのレイアウトを変更する方法を紹介します。 ...
RecyclerViewは表示が変更される(アイテムの更新、スクロール)時、アイテムのViewをリサイクル(再生利用)します。 これにより余分なViewの作成が行われなくなり、メモリーの節約とパフォーマンスの向上が望めます。 リサイクルはCachedViewsとRecyclerPoolという2つのキャッシュで行われます。 このキャッシュを使ったリサイクルの動作を調べたので紹介します。 ...
RecyclerViewはアイテムを一覧表示してくれます。 ただ一覧表示するだけではなく、「追加・削除・移動・切り替え」といったアイテムの表示を効率よく変更する仕組み持っています。 今回はこの仕組みを使ったアイテムの変更方法を紹介します。 ...
RecyclerViewのリサイクル動作で使われるキャッシュは、サイズを大きくすれば多くのViewHolderが保持できます。その分、多くのメモリを消費します。 ViewHolderを多く保持できたとしても、サイクル動作で効率よく使われなければ、メモリの浪費です。 キャッシュのサイズはRecyclerViewの使われ方よって適切なサイズがあります。 そのため、RecyclerViewはキャッシュのサイズを変更できるようになっています。 ...
RecyclerViewが空(アイテムが無い)の時、EmptyViewを表示する実装を行ったので紹介します。 ...
RecyclerView上のアイテムを選択する方法を紹介します。 外部ライブラリー(AndroidX)で提供されるrecyclerview-selection APIを用いた方法です。 ...
RecyclerViewはListView(RecyclerViewの前身)の時に存在していたChoiceModeがありません。 同様な機能が欲しければプログラマ側で実装しなければなりません。 RecyclerView.AdapterをカスタマイズしてChoiceModeを実装してみたので紹介します。 ...
RecyclerViewはアイテムへ装飾を付けることが出来るようになっています。 装飾とは、例えばアイテムの区切り線などです。 今回はアイテムへ装飾を付ける方法を紹介します。 ...
RecyclerViewに表示しきれなかったアイテムはスクロールを行うことで表示されるようになっています。 スクロールは「外部入力(指でスクリーン上をタッチしてスライド)によるスクロール」の他に、「プログラムによるスクロール」をすることも出来ます。 今回はこのアイテムのスクロールについてまとめてみました。 ...
RecyclerViewはアイテムをスクロールさせて隠れたアイテムを表示できます。 スクロールを止める位置は任意です。 任意であるがゆえに、止めた位置によってはアイテムの一部が欠けてしまうこともあります。 携帯端末の画面は狭いので、効率よくコンテンツの表示を行いたいとアプリ開発者は考えます。 アイテムの一部が欠けてしまうことは、効率が良いとは言えません。 このような問題を解決するために、アイテムのスナップをRecyclerViewへ追加できます。 アイテムのスナップを追加する方法を紹介します。 ...
RecyclerViewでアイテムの変更(Change/Insert/Move/Remove)を行うと、変更される様子がアニメーション化されています。 これはデフォルトでアイテムの変更アニメーションが組み込まれているためです。 デフォルトは単純なアニメーションですが、「ある」と「ない」の違いは歴然で、アニメーションのある方が高価なアプリケーションに見えます。 GUI(Graphical User Interface)が主体の携帯端末にとって、利用者に対するアプリの見せ方は重要です。高価に見えた方が使ってもらえる可能性が高くなります。 上記のことから、アプリの機能に関係なくても、ちょっとした動きをアニメーション化するメリットがあります。 2回にわたりアイテムの変更アニメーションについてまとめてみました。 アイテムの変更アニメーション(DefaultItemAnimator、デフォルト) アイテムの変更アニメーション(SimpleItemAnimatorの継承、カスタム) 今回は第1回目「ItemAnimator、デフォルト」編です。デフォルト変更アニメーションの動作について説明します。 ...
RecyclerViewでアイテムの変更(Change/Insert/Move/Remove)を行うと、変更される様子がアニメーション化されています。 これはデフォルトでアイテムの変更アニメーションが組み込まれているためです。 デフォルトは単純なアニメーションですが、「ある」と「ない」の違いは歴然で、アニメーションのある方が高価なアプリケーションに見えます。 GUI(Graphical User Interface)が主体の携帯端末にとって、利用者に対するアプリの見せ方は重要です。高価に見えた方が使ってもらえる可能性が高くなります。 上記のことから、アプリの機能に関係なくても、ちょっとした動きをアニメーション化するメリットがあります。 2回にわたりアイテムの変更アニメーションについてまとめてみました。 アイテムの変更アニメーション(DefaultItemAnimator、デフォルト) アイテムの変更アニメーション(SimpleItemAnimatorの継承、カスタム) 今回は第2回目「SimpleItemAnimatorの継承、カスタム」編です。カスタム変更アニメーションの作り方を説明 ...
RecyclerViewへアイテムが表示されるとき、アニメーションはありません。。一瞬で表示されて終わりです。 「RecyclerViewへアイテムが表示される」ことを、ここでは「アイテムの出現」と言い表すことにします。 このアイテムの出現にアニメーションを付ける方法を紹介します。 アイテムの出現をアニメーションで演出することで、RecyclerViewに表示したい内容が際立つと思います。 ...
RecyclerViewで「画像ファイルをグリッド表示」する方法を、まとめます。 スマートフォンのアプリを作っていると、何度も遭遇するテクニックです。 ※環境:Android Studio Ladybug | 2024.2.1 Patch 1     Kotlin 2.0.0     Compose Compilerプラグイン 2.0.0     androidx.recyclerview:recyclerview:1.1.0 ...
RecyclerViewで「グリッド表示をスムーズにスクロール」する方法について、まとめます。 画像ファイルをグリッド表示する場合は、スムーズなスクロールを行うための工夫が必要です。 その工夫について紹介します。 ※環境:Android Studio Ladybug | 2024.2.1 Patch 1     Kotlin 2.0.0     Compose Compilerプラグイン 2.0.0     androidx.recyclerview:recyclerview:1.1.0 ...
スポンサーリンク