Android Kotlin基礎講座 07.2:DiffUtilとRecycleViewのデータバインディング
目次
タスク:開発の開始とここまでの確認
前回の記事で作成したアプリを引き続き使うこともできますし、GitHubからRecyclerViewDiffUtilDataBinding-Starter appをダウンロードして使っていただいても構いません。
- 必要な方はGitHubからRecyclerViewDiffUtilDataBinding-Starter appをダウンロードし、Android Studioで開いてください。
- アプリを起動させてください。
- SleepNightAdapter.ktファイルを開いてください。
- アプリの構造を理解するために、コードを確認します。ユーザーにデータを表示するためにアダプターパターンを用いたRecyclerViewの使用方法の要約が以下のダイアグラムに記されています。

- ユーザーインプットからアプリはSleepNightオブジェクトのリストを作成します。
それぞれのSleepNightオブジェクトは一夜分データである、睡眠時間、睡眠の質を表しています。 - SleepNightAdapterはSleepNightオブジェクトのリストをRecyclerViewが表示できるように適合させる役割を担っています。
- SleepNightAdapterはビュー、データ、RecyclerViewがデータを表示するためのメタ情報を含んだViewHolderを生成します。
- RecyclerViewはSleepNightAdapterを使っていくつのアイテムを表示するのかを決定します(getItemCount())。RecyclerViewはonCreateViewHolder()とonBindViewHolder()を使ってビューホルダーを表示するデータにバインドします。
notifyDataSetChanged()メソッドは非効率的
RecyclerViewにリスト内のアイテムが変更され、更新される必要があることを伝えるために、現在のコードは以下で示されているようにSleepNightAdapter内のnotifyDataSetChanged()を呼び出しています。
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
しかしながら、notifyDataSetChanged()はRecyclerViewにリスト全体が無効である可能性があることを伝えています。結果として、RecyclerViewは画面に映っていないアイテムも含んだリストのアイテム全てをリバインドし、再描写しています。これは膨大な無駄と言えるでしょう。膨大または複雑なリストに対して、この処理には、ユーザーがリストをスクロールするときに表示がちらついたり、途切れたりするほど時間がかかる場合があります。
この問題を修正するために、RecyclerViewに正確に何が変更されたのかを伝える必要があります。そうすることでRecyclerViewはそのビューだけを更新することができます。
RecyclerViewは単体の要素を更新するためのAPIを持っています。notifyItemChanged()を使ってRecylerViewにアイテムが変更されたことを伝えることができます。また、似たような関数を使ってアイテムが追加されたこと、削除されたこと、移動されたことなどを伝えることができます。全て手動で行うこともできますが、そのタスクは簡単ではなく、かなりのコードが含まれる可能性があります。
幸いなことに、手動で行うよりもより良い方法があります。
DiffUtilは効率的で難しい作業をこなしてくれる
RecyclerViewはDiffUtilという二つのリスト間の差を計算するためのクラスをもっています。DiffUtilは古いリストと新しいリストを受け取り、何が違っているのかを明らかにしてくれます。つまり追加、削除、変更されたアイテムを見つけてくれるということです。その後にマイヤーズの差分アルゴリズムを用いて、古いリストから新しいリストを生成するために必要な最小変更数を導き出してくれます。
DiffUtilが違っている部分を発見してくれた後は、RecyclerViewがその情報を使って変更、追加、削除、または移動されたアイテムのみを更新することができます。これはリスト全体を更新するよりも大幅に効率的であると言えます。