はじめに
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しているコードがあってなるほどなぁと思った。
Flow
にonStart()
や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
型になっている。PagingData
はFlow<PageEvent<T>>
型であるflowとUiReceiverをもつPagingData
の生成はPager.flow
から取ってくることができるPager.flow
はPageFetcher.flow
から作られているPageFetcher.flow
はKotlin Coroutineがchainになっていて読んでて楽しい。
- 実際の処理は
AsyncPagingDataDiffer
に移譲している
- 引数は
Flow<Unit>
型のdataRefreshFlow
が生えていてアプリケーションはこれをcollectしてdataの更新を検知することができる
2. AsyncPagingDataDiffer
PagingDataDiffer
を持っていてdiffを計算してくれる- diffの計算は
Dispatchers.Main
のcontextで走る
- diffの計算は
- 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が発火する。 イベント発火後、AsyncPagingDataDiffer
でPresenterCallback
はrecycler viewのListUpdateCallback
に変換されてリストが更新される。