Paging 3 に移行する

Paging 3 は、以前のバージョンのページング ライブラリとは大きく異なります。 このバージョンでは拡張機能が提供されており、Kotlin のコルーチンと Flow の最高級のサポート、Jetpack Compose とのシームレスな統合が実現しています。

Paging 3 に移行するメリット

Paging 3 では、旧バージョンのライブラリにはない以下の機能を利用できます。

  • Kotlin のコルーチンと Flow の最高級のサポート。
  • レスポンシブ UI 設計のための組み込みの読み込み状態およびエラー信号(再試行および更新機能を含む)。
  • リポジトリ レイヤの改善。キャンセルのサポートやシンプルなデータソース インターフェースなど。
  • プレゼンテーション層、リスト セパレータ、カスタムページ変換、ヘッダーとフッター、Lazy リストの読み込み状態アイテムの改善。

アプリを Paging 3 に移行する

Paging 3 に完全に移行するには、Paging 2 から次の主要コンポーネントを移行する必要があります。

  • DataSource クラス
  • PagedList
  • プレゼンテーション層(LazyPagingItems

ただし、Paging 3 コンポーネントの中には、以前のバージョンの Paging と下位互換性があるものもあります。特に、Pager API では、古い DataSource オブジェクトを asPagingSourceFactory メソッドで使用できます。そのため、以下のような移行が可能です。

  • DataSourcePagingSource に移行して、残りの Paging の実装を変更しない。
  • Paging の実装全体を移行して、アプリを Paging 3 に完全に移行する。

このページのセクションでは、アプリの各レイヤで Paging コンポーネントを移行する方法について説明します。

DataSource クラス

このセクションでは、古い Paging の実装を移行して PagingSource を使用するために必要なすべての変更について説明します。

Paging 2 の PageKeyedDataSourcePositionalDataSourceItemKeyedDataSource はすべて、Paging 3 の PagingSource API に統合されています。すべての古い API クラスの読み込みメソッドは、PagingSource 内の単一の load メソッドに統合されています。これにより、コードの重複が減少します。これは、古い API クラスの実装における読み込みメソッド全体のロジックの多くが同一であることがよくあるためです。

すべての読み込みメソッドのパラメータは、Paging 3 で LoadParams シールクラスに置き換えられます。このクラスには、各読み込み型のサブクラスが含まれます。`load` メソッド内の読み込み型を区別する必要がある場合は、LoadParams のどのサブクラス(LoadParams.RefreshLoadParams.PrependLoadParams.Append)が渡されたかを確認します。

PagingSource の実装について詳しくは、データソースを定義するをご覧ください。

キーを更新する

PagingSource の実装では、読み込まれたページング データの途中の状態から更新を再開する方法を定義する必要があります。そのためには、 getRefreshKey を実装し、最近アクセスしたインデックスとしてstate.anchorPositionを使用して、正しい初期キーをマッピングします。

// Replaces ItemKeyedDataSource.
override fun getRefreshKey(state: PagingState<String, User>): String? {
  return state.anchorPosition?.let { anchorPosition ->
    state.getClosestItemToPosition(anchorPosition)?.id
  }
}

// Replacing PositionalDataSource.
override fun getRefreshKey(state: PagingState<Int, User>): Int? {
  return state.anchorPosition
}

変換を一覧表示する

ページング ライブラリの旧バージョンでは、ページング データの変換は次のメソッドに依存しています。

  • DataSource.map
  • DataSource.mapByPage
  • DataSource.Factory.map
  • DataSource.Factory.mapByPage

Paging 3 では、すべての変換は PagingData に対する演算子として適用されます。上記リストのいずれかのメソッドを使用してページング リストを変換している場合は、新しい PagingSource を使用して Pager を作成するときに、変換ロジックを DataSource から PagingData に移動する必要があります。

Paging 3 でページング データに変換を適用する方法については、 データ ストリームを変換するをご覧ください。

PagedList

このセクションでは、古い Paging の実装を移行して Paging 3 で PagerPagingData を使用するために必要なすべての変更について説明します。

PagedListBuilder クラス

PagingData は、Paging 2 の既存の PagedList に代わるものです。PagingData に移行するには、以下を更新する必要があります。

  • Paging の設定が PagedList.Config から PagingConfig に移動されました。
  • 古いビルダー クラスが単一の Pager クラスに統合されました。
  • Pager は、.flow プロパティを含むオブザーバブルな Flow<PagingData> を公開します。
val flow = Pager(
  // Configure how data is loaded by passing additional properties to
  // PagingConfig, such as prefetchDistance.
  PagingConfig(pageSize = 20)
) {
  ExamplePagingSource(backend, query)
}.flow
  .cachedIn(viewModelScope)

Paging 3 で PagingData オブジェクトのリアクティブ ストリームを設定する方法について詳しくは、PagingData のストリームを設定するをご覧ください。

階層化されたソース用の BoundaryCallback

Paging 3 では、ネットワークおよびデータベースからのページングのハンドラとして、PagedList.BoundaryCallbackRemoteMediator に置き換わります。

RemoteMediator を使用して Paging 3 のネットワークとデータベースからページングする方法については、Android ページングの Codelab をご覧ください。

LazyPagingItems

このセクションでは、古い Paging の実装を移行して Paging 3 の LazyPagingItems を使用するために必要なすべての変更について説明します。

Paging 3 には、新しい PagingData フローを処理する collectAsLazyPagingItems が用意されています。プレゼンテーション層を移行するには、paging-compose アーティファクトと collectAsLazyPagingItems を使用して PagingData アイテムを収集し、@Composable 関数で表示します。

LazyPagingItems の詳細については、ページング データを読み込む、表示するをご覧ください。

リストの差分と更新

現在カスタムのリスト差分ロジックを使用している場合は、Paging 3 で提供される LazyPagingItems を使用するように実装を移行します。差分が正しく行われるようにするには、Lazy リストにアイテムキーを指定します。

@Composable
fun UserScreen(viewModel: UserViewModel) {
    // Collects the Flow into a LazyPagingItems object
    val lazyPagingItems = viewModel.pager.flow.collectAsLazyPagingItems()

    UserList(lazyPagingItems)
}

@Composable
fun UserScreen(viewModel: UserViewModel) {
    val lazyPagingItems = viewModel.pager.flow.collectAsLazyPagingItems()

    UserList(lazyPagingItems)
}

@Composable
fun UserList(lazyPagingItems: LazyPagingItems<User>) {
    LazyColumn {
        items(
            count = lazyPagingItems.itemCount,
            // Provide a stable key for each item, similar to DiffUtil in Views
            key = lazyPagingItems.itemKey { user -> user.id } 
        ) { index ->
            val user = lazyPagingItems[index]
            if (user != null) {
                UserRow(user = user)
            }
        }
    }
}

アイテムキーの詳細については、アイテムキーをご覧ください。

読み込み状態

Paging 3 では、読み込み状態のヘッダーまたはフッターを表示するために別のアダプターは必要ありません。LazyPagingItems オブジェクトは、LazyColumn 内で直接確認できる loadState プロパティを公開します。

LazyColumn {
    // ... items(lazyPagingItems) go here ...

    // Show loading spinner at bottom of list when appending data
    if (lazyPagingItems.loadState.append is LoadState.Loading) {
        item {
            CircularProgressIndicator(modifier = Modifier.fillMaxWidth())
        }
    }
}

参考情報

ページング ライブラリについて詳しくは、以下の参考情報をご覧ください。

ドキュメント

Views のコンテンツ