Paging Library + API + データ追加/削除
データ追加/削除が絡む、Paging Library + APIは単純にはいかないので、工夫が必要です。
Paging Library自体の説明は省略します。
環境
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0-rc01'
implementation 'androidx.paging:paging-runtime:2.0.0-rc01'
implementation 'androidx.room:room-runtime:2.0.0-rc01'
kapt 'androidx.room:room-compiler:2.0.0-rc01'問題点
PagedList は基本的にあとから追加/削除ができず、データを追加したり、削除したりする場合は、再生成する必要があります。
ほとんどのケースでAPI通信の場合は、 PageKeyedDataSource か ItemKeyedDataSource を使うことになると思います。
DataSource#invalidate で、単純に再生成すると、1ページ目から取得することになります。例えば、5ページ目にあるデータを削除した場合にまた1ページ目が表示されてしまう感じになってしまいます。
解決策
こういった問題はRoomを組み合わせることで解決することができます。Roomをキャッシュに使うような実装とほぼ同じです。
PagingのDataSourceにはRoomを使い、APIから取得したデータをRoomへ書き込んでいきます。
データ追加/削除が必要なときは、APIへリクエストしつつ、Room側のデータを追加/削除することで、表示も問題なく行うことが可能になります。
以下に実装時のポイントを少しだけ。
実装ポイント
BoundaryCallback
Paging Libraryには BoundaryCallback というものがあり、 PagedList が最後まで来た場合に通知をしてくれるものです。
これを使うことで、RoomのデータがないときにAPI通信を行いRoomへ書き込む処理が可能になります。
以下のような感じになってます。
これを LivePagedListBuilder#setBoundaryCallback に渡すと通知が来るようになります。
RoomのPaging
RoomはPagingに対応していて、Roomの実装自体は簡単にできます。
Daoでクエリの戻り値に DataSource.Factory を指定することでPaging可能になります。
RoomのPagingはデータの変更を監視していて、データの変更が行われると、 DataSource#invalidate が呼ばれて、 PagedList が再生成される様になっています。(コード)
また、RoomのDataSourceには PositionalDataSource が使われていて、 loadInitial で必要なポジションとページサイズを求めて取得するようになっています。(コード)
サンプル
簡単なサンプルを作りました。Redditからデータ取得して、Deleteボタンで行削除ができるやつです。
data.repository パッケージ内を見てもらえるとだいたい分かるかなと。
