ここのところ諸事情があってPagingライブラリの開発中コードを見に行っていたのですが、面白そうな変更が入っていたので技術メモ。 まだalphaにもなっていないのでまだまだ変更はあるだろうし、リリースされないかもしれません。
PagedListがPagedDataへ
PagedList
*1 が PagingData
*2 に置き換えになります。
大抵の場合 PagingList
も PagedData
も直接いじることはありません。
つまりRepository層でPagingライブラリを利用して作成したらRecyclerViewのAdapterにそのまま渡すだけ、と考えられるため実装上では影響はほぼありません。
@Deprecated("PagedList is deprecated and has been replaced by PagingData") abstract class PagedList<T : Any> internal constructor( /** * The [PagingSource] that provides data to this [PagedList]. * * @suppress */ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) open val pagingSource: PagingSource<*, T>, internal val storage: PagedStorage<T>, /** * Return the Config used to construct this PagedList. * * @return the Config of this PagedList */ val config: Config ) : AbstractList<T>() {
class PagingData<T : Any> internal constructor( internal val flow: Flow<PageEvent<T>>, internal val receiver: UiReceiver ) {
すんごい余談になりますが、今年のDroidKaigiへ出したネタの中で一番自信があったのが「Pagingライブラリと組み合わせるならPagedListAdapterとGroupieとEpoxyのどれがいいの?」という話でした。
RecyclerView.Adapter
を独自に拡張してPagingライブラリへの対応を行っていたりする場合、ライブラリ側で対応するためにはKotlin Coroutinesをライブラリの依存関係に追加することが必要になりそうです。
今回の更新により、結論は PagingDataAdapter
を使う話になりそうですね。なんてこったい。
PagedListAdapterがPagingDataAdapterへ
PagedListAdapter
*3 も PagingDataAdapter
*4 に変わっています。
@Deprecated( message = "PagedListAdapter is deprecated and has been replaced by PagingDataAdapter", replaceWith = ReplaceWith( "PagingDataAdapter<T, VH>", "androidx.paging.PagingDataAdapter" ) ) abstract class PagedListAdapter<T : Any, VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH> { /** * Creates a [PagedListAdapter] with default threading and * [androidx.recyclerview.widget.ListUpdateCallback]. * * Convenience for [PagedListAdapter], which uses default threading behavior. * * @param diffCallback The [DiffUtil.ItemCallback] instance to * compare items in the list. */ protected constructor(diffCallback: DiffUtil.ItemCallback<T>) { @Suppress("DEPRECATION") differ = AsyncPagedListDiffer(this, diffCallback) differ.addPagedListListener(listener) } protected constructor(config: AsyncDifferConfig<T>) { @Suppress("DEPRECATION") differ = AsyncPagedListDiffer(AdapterListUpdateCallback(this), config) differ.addPagedListListener(listener) }
abstract class PagingDataAdapter<T : Any, VH : RecyclerView.ViewHolder>( diffCallback: DiffUtil.ItemCallback<T>, mainDispatcher: CoroutineDispatcher = Dispatchers.Main, workerDispatcher: CoroutineDispatcher = Dispatchers.Default ) : RecyclerView.Adapter<VH>() {
AsyncDifferConfig
をセットしていたケースでは修正が必要になるっぽいのですが、大抵の場合 DiffUtil.ItemCallback
を使うので置き換えは簡単そうな見込みです。
一方で当然のように Dispatchers.Main
がdefault valueとして指定されているなど、構造がマルっと変わっています。
Kotlin CoroutinesがPagingライブラリに導入されていく話はKotlin愛好会の技術同人誌*5に寄稿しているので、興味があればお手に取ってみてください。(露骨な宣伝)
これまた余談なのですが MergeAdapter
が入っていたりと、いくつか実装の参考にできそうなところもあります。
/** * Create a [MergeAdapter] with the provided [LoadStateAdapter]s displaying the * [LoadType.START] and [LoadType.END] [LoadState]s as list items at the start and end * respectively. * * @see LoadStateAdapter * @see withLoadStateHeader * @see withLoadStateFooter */ fun withLoadStateHeaderAndFooter( header: LoadStateAdapter<*>, footer: LoadStateAdapter<*> ): MergeAdapter { addLoadStateListener { loadType, loadState -> if (loadType == LoadType.START) { header.loadState = loadState } else if (loadType == LoadType.END) { footer.loadState = loadState } } return MergeAdapter(header, this, footer) }
カスタムのAdapterを作るときに、参考にしていけそうです。たのしみ。
PageKeyed / ItemKeyed / PositionalDataSourceがPagingSourceへ
DataSource
の実装である PageKeyedDataSource
*6 , ItemKeyedDataSource
*7 と PositionalDataSource
*8 が PagingSource
*9 に置き換えられます。
この影響は loadInitial
loadBefore
loadAfter
の各メソッドで書き分けられていた処理が load
メソッドにまとめられ、 LoadType
*10 で処理を分ける形に変わります。
enum class LoadType { /** * [PagingData] content being refreshed, which can be a result of [PagingSource] * invalidation, refresh that may contain content updates, or the initial load. */ REFRESH, /** * Load at the start of a [PagingData]. */ START, /** * Load at the end of a [PagingData]. */ END }
小さな変更ですが、Pagingライブラリの更新で書き換えが発生する個所となります。
load
が suspend
になることと合わせて、簡単な更新の準備をしておいた方が良さそうです。
おわりに
正式リリースが楽しみです。 首を長くして待ちたいなと思います。
*1:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
*2:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/PagingData.kt
*3:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
*4:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/runtime/src/main/java/androidx/paging/PagingDataAdapter.kt
*6:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/PageKeyedDataSource.kt
*7:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/ItemKeyedDataSource.kt
*8:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/PositionalDataSource.kt
*9:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/PagingSource.kt
*10:https://android.googlesource.com/platform/frameworks/support/+/2a9a199e0b4b2967f3e7446c29bd97ec2d7510f9/paging/common/src/main/kotlin/androidx/paging/LoadType.kt