言いたいことはそれだけか

KotlinとかAndroidとかが好きです。調べたことをメモします。٩( 'ω' )و

Paging Library 3の内部実装読んだメモ書き

はじめに

Paging Library 3が発表された際、Full Kotlinで書かれてCoroutineもたくさん使われているということで話題になった。せっかくなので内部実装を読んでみた時のメモを雑に残しておく。

今回みたバージョンは 3.0.0-alpha01

PagingLibraryをどう使うかは下記のCodelabを参考にした。

codelabs.developers.google.com

学びメモ

  • 今までRxJavaで「Signalをemitしたい(emitされるvalueに意味はない場合 e.g. ユーザのclickを検出したい時とか)場合」にboolean trueとか適当な値を流していたけど、Kotlin CoroutineのflowでUnit型をemitしているコードがあってなるほどなぁと思った。
  • FlowonStart()onCompletion(), onEmpty() などの拡張関数が生えている。onEmpty()ってどういう時に使いたくなるんだろう
  • class内部では ConflatedBroadcastChannel を使っていて、拡張関数ConflatedBroadcastChannel.asFlow()を使って外部に提供している部分がたくさんある
  • 上記で提供されるflowは拡張関数 Flow.asLiveData() を使ってLiveDataに変換することができる
  • LiveData.switchMap() を使ってMutableLaveData A にvalue a がpostされたタイミングでそのvalueを使って何か処理を行い Mutable Live Data B にtransformしたvalue b をpostすることができる
  • Flow.scan() 便利。initial valueにnullを入れる場合は null as MulticastedPagingData<T>? のようにnullをcastして渡していた
  • MergedAdapterは次のversionくらいでConcatAdapterに変更されるっぽい。PagingDataAdapter.withLoadStateHeaderAndFooter()MergedAdapterを返却しているので注意。(rename前の今も実際の挙動はmergeではなくconcat)

実装の詳細メモ

1. PagingDataAdapter

  • RecyclerView.Adapter をextendしている
  • submitData() がトリガーとなってdetaがセットされる
    • 引数は PagingData 型になっている。
      • PagingDataFlow<PageEvent<T>> 型であるflowとUiReceiverをもつ
      • PagingDataの生成はPager.flow から取ってくることができる
        • Pager.flowPageFetcher.flow から作られている
          • PageFetcher.flow はKotlin Coroutineがchainになっていて読んでて楽しい。
    • 実際の処理は AsyncPagingDataDiffer に移譲している
  • Flow<Unit> 型の dataRefreshFlow が生えていてアプリケーションはこれをcollectしてdataの更新を検知することができる

2. AsyncPagingDataDiffer

  • PagingDataDiffer を持っていてdiffを計算してくれる
    • diffの計算は Dispatchers.Main のcontextで走る
  • Kotlin coroutineのjobを持っていて複数のdiff計算が走らないように制御してくれる

3. PagingDataDiffer

  • abstract classなので、実際はこれを実装したobjectが AsyncPagingDataDiffer クラスに定義されている
  • suspend funである collectFrom() を持っている。PagingDataのflowからデータを取得してDispatchers.Main のcontextでdiffを計算しPageEventの種類によってPagePresenterにinsert/dropのeventを処理させる。

4. PagePresenter

  • page情報を保持するクラスで NullPaddedListを実装している
  • PresenterCallback というinterfaceを持っていて、dataが更新されるとこのcallbackが発火する。 イベント発火後、AsyncPagingDataDifferPresenterCallback はrecycler viewの ListUpdateCallback に変換されてリストが更新される。