迁移到 Paging 3

Paging 3 与旧版 Paging 库存在很大区别。 此版本提供了增强型功能,为 Kotlin 协程和 Flow 提供一流的支持,并与 Jetpack Compose 无缝集成。

迁移到 Paging 3 的优势

Paging 3 包含旧版库中没有的下列功能:

  • 为 Kotlin 协程和 Flow 提供一流的支持。
  • 针对自适应界面设计的内置加载状态和错误信号,包括重试和刷新功能。
  • 改进了代码库层,包括取消支持和简化的数据源界面。
  • 改进了表示层、列表分隔符、自定义页面转换、页眉和页脚,以及延迟列表的加载状态项。

将应用迁移到 Paging 3

为了完全迁移到 Paging 3,您必须从 Paging 2 迁移以下主要组件:

  • DataSource
  • PagedList
  • 表示层(到 LazyPagingItems

不过,某些 Paging 3 组件向后兼容旧版 Paging。特别是,Pager API 可以使用带有 asPagingSourceFactory 方法的旧版 DataSource 对象。这意味着,您有以下迁移选项:

  • 您可以将 DataSource 迁移到 PagingSource,但让 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.Prepend 还是 LoadParams.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
}

列表转换

在较低版本的 Paging 库中,分页数据的转换依赖于以下方法:

  • 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,您必须完成以下更新:

  • 将分页配置从 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 中,RemoteMediator 取代 PagedList.BoundaryCallback 作为 a 处理从网络和数据库分页的处理程序。

如需详细了解如何在 Paging 3 中使用 RemoteMediator 从网络和数据库分页,请参阅 Android Paging Codelab

LazyPagingItems

本部分介绍迁移旧版 Paging 实现以使用 Paging 3 中的 LazyPagingItems 所需的所有更改。

Paging 3 提供 collectAsLazyPagingItems 来处理新的 PagingData 流。如需迁移表示层,请使用 paging-compose 工件和 collectAsLazyPagingItems 来收集 PagingData 项,并在 @Composable 函数中显示这些项。

如需详细了解 LazyPagingItems,请参阅 加载并显示分页数据

列表差异和更新

如果您目前使用自定义列表差异逻辑,请迁移您的实现以改用 Paging 3 中提供的 LazyPagingItems。为了确保正确进行差异比较,请在延迟列表中指定项键:

@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 对象公开了一个 loadState 属性,您可以在 LazyColumn 中直接检查该属性。

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())
        }
    }
}

其他资源

如需详细了解 Paging 库,请参阅下列其他资源:

文档

查看内容