0
0

RecyclerView.ViewHolderのライフサイクル

Last updated at Posted at 2024-09-01

通常は意識する必要は無いと思いますが、RecyclerViewのViewごとに表示状態のログを取ったり、非同期処理の後片付けを行いたいなどの理由で、正確なライフサイクルを知りたい場合もあるかと思います。
まあ、そういう状況になったので調べましたというエントリーです。

ViewHolderのライフサイクルイベント

ViewHolder自身にはイベントを受け取る仕組みはありませんが、RecyclerView.Adapterがそれぞれのイベント受け取っているため、必要に応じてViewHolderへ伝えるように実装できます。

スクロール

RecyclerViewをスクロールしていった時に発生するイベントは以下のようになります。

セルの表示

onCreateViewHolder
ViewHolderを作成する。この時点ではViewTypeのみ確定でどのデータを表示するかは決まっていない。名前の通りリサイクルされるため、表示に必要な数+キャッシュ分しか作られず、作成済みのインスタンスが使い回される。

onBindViewHolder
ここで表示位置が確定し、その位置に対応するデータと紐付けて表示などを変更する

onViewAttachedToWindow
実際に表示される

セルが画面外に出る

onViewDetachedFromWindow
非表示になる

再利用開始

onViewRecycled
Detachされて即座にリサイクルされるわけではありません、再表示のためにしばらく保留されます。
画面外に出て十分に離れた場所までスクロールしたときに、リサイクルが行われます。

別のセルへの再利用

onBindViewHolder
リサイクルが行われ、別のセルの表示のために利用されます。表示する位置が指定され、そのデータを紐付け、表示を変更します。

onAttachedToWindow
新しいデータでViewが表示される


上記のような順序でライフサイクルイベントが発生します

データの変更

RecyclerViewでデータの変更が伴う場合、Viewすべての作り直しでは無く、更新されるポイントに絞って更新を行うのが通常です。操作が限定的な場合以外は、notifyItemXXXメソッドを使うのではなく、DiffUtilsやListAdapterを使うことが多いでしょう。この状況でデータ列に変更を加えた場合にどうなるかを調べました。

なお、ItemAdapterにて、アニメーションを行うために新しいViewHolderが作られてしまう場合があります。デフォルトのSimpleItemAnimatorの場合、以下のようにすることで、この挙動を抑制することができます。この状態で検証してみます。

(recyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false

並べ替え

個々のデータは変化せず、順序が入れ替わった場合です。

(並べ替えの結果表示される要素が変化しない場合)何も呼び出されません。
ViewHolderが保持するViewの表示位置が変更されただけですから何も呼び出されません

要素の削除

データ列から要素を削除した場合です。

onViewDetachedFromWindow
onViewRecycled
削除されたデータに対応するViewが表示されている場合、onViewDetachedFromWindowとonViewRecycledがコールされます。

要素の追加

データ列に新しい要素を追加した場合です。

onCreateViewHolder
onBindViewHolder
onViewAttachedToWindow

ViewHolderが作成済みのキャッシュから使われる場合は、onCreateViewHolderが呼ばれないですが、
新規要素が表示された場合と同様です。追加されたことで画面外にで多要素がある場合は、スクロールと同様です。

コンテンツの変更

同一のデータであるが、内容が異なると判定される変化があった場合です。

onBindViewHolder
対象のViewHolderに対してonBindViewHolderが呼び出されますので、ここで表示コンテンツを書き換えます。

別データとの入れ替え

一部のデータが別のデータであると判定される内容に変化した場合です。

旧要素について
onViewDetachedFromWindow
onViewRecycled

新要素について
onCreateViewHolder
onBindViewHolder
onViewAttachedToWindow

扱いとしては、要素が削除されて別の要素が追加された、という扱いになるので削除と追加の挙動が発生します。

ViewTypeが異なるデータとの入れ替え

異なるViewHolderと入れ替えられる言うだけで、別データとの入れ替えと全く同じなので省略

まとめ

まとめると以下のようなライフサイクルになっています。

具体的な例で言えば、

表示の開始、終了をロギングする場合は、
onViewAttachedToWindow、onViewDetachedFromWindowを監視する

表示データが画像のURLでそのダウンロードを非同期に行う場合、
onBindViewHolderで開始
onViewRecycledか、次のonBindViewHolderでそのタスクのキャンセルを実行する

といった使い方になりそうですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0