RemoteMediatorの概要とその利用準備
本連載は、Android Jetpackを紹介しています。今回は、大量のデータを効率よく扱えるページングライブラリを利用して、ネット上にあるリストデータをいったんデータベースに格納した上でページングする方法を解説します。
なお、今回のサンプルデータは、GitHubから参照できます。ただし、サンプル内のコードでは実際にネットにアクセスしてデータを取得するコードは記載せず、ダミーでデータを生成するコードとなっている点はあらかじめご了承ください。
PagingSourceクラスとネットアクセスの問題点
前回紹介したように、PagingSourceクラスを自作し、その中にネット上のリストデータを取得するコードを記述すれば、ネット上にある大量のデータをページングしながら表示することが可能です。
ただし、この方法には問題があります。まず、当たり前ですが、オフラインの時にはデータを取得できません。さらに、リストを前のページに戻した時、すなわち以前表示したデータを再表示する際にもネットアクセスが発生してしまいます(※)。
※実際にはメモリ上にリストデータが存在するのですぐにアクセスが発生するわけではありません。
Androidにはオフラインファーストという考え方があります。これはすなわち、可能な限りオフラインでもデータ表示が可能なことを前提にアプリを作成する考え方です
先述の問題を解決し、オフラインファーストを実現するならば、いったん取得したネット上のリストデータはデータベースに格納した上で、そのデータを表示する必要があります。つまり、データベースへのキャッシュが有効です。
そしてページングライブラリには、これを効率よく実現してくれる仕組みがあります。
RemoteMediatorの働き
それが、RemoteMediatorクラスです。
RemoteMediatorクラス内では、ページングライブラリから呼び出された際にデータベース内の現在のデータの状態を確認し、それに基づいて続きのデータをネット上から取得し、データベースに格納します。
そのデータベースのデータを元に生成されたPagingSourceを利用することで、第12回で紹介した内容と同じく、ページング表示が可能になります(図1)。
この仕組みにより、ネット上のデータをデータベースにキャッシュしながらページング表示が可能です。

ここから、実際にRemoteMediatorの使い方を紹介していきます。
その際の題材は、前回と第12回の組合せのようなものです。ネット上から電話番号リストを取得し、それをデータベース上のphonesテーブルにキャッシュすることにします。
したがって、第12回で登場したRoomによるphonesテーブルの操作に必要なクラスや、前回登場したネット上のリストデータを取得するsuspend関数(Javaの場合はCallableインターフェースを実装したクラス)が、そのまま登場します。
DAOにメソッドを追加
ただし、PhoneDAOには改造が必要です。というのは、RemoteMediatorを利用する場合、前項での説明の通り、RemoteMediator内でネット上から取得したデータをデータベースに格納するコードを記述する必要があります。
そのためには、DAOインターフェースにそのメソッドを追加しておく必要があります。これは例えばリスト1のコードとなります。
@Dao interface PhoneDAO { @Query("SELECT * FROM phones ORDER BY id") // (1) fun findAll(): PagingSource<Int, Phone> // (1) @Insert(onConflict = OnConflictStrategy.REPLACE) // (2) suspend fun insertPhoneList(phones: List<Phone>) // (2) @Query("DELETE FROM phones") // (3) suspend fun deleteAll() // (3) @Query("SELECT MAX(id) FROM phones") // (4) suspend fun findLastId(): Long // (4) }
リスト1の(1)は、第12回のリスト2にも記述されていたメソッドです。
これに(2)~(4)が追加されています。前項で紹介したように、RemoteMediatorではネット上から取得したリストデータをデータベースに格納する必要があります。そのメソッドが(2)です。アノテーションにデータのコンフリクトが起きた際は、丸々置き換えるようにしてあるのがポイントです。
(3)は全データの削除メソッドです。RemoteMediator内のコーディングの際に紹介するように、キャッシュのクリアの意味でデータベース内の全データを削除するタイミングがあります。その際に利用するメソッドです。
(4)は、データベース内のidの最大値を取得するメソッドです。この結果を元に、データベース内にどこまでのリストデータが格納されているのかを判断し、続きをネット上から取得するようにします。