迁移到 Paging 3

Paging 3 与早期版本的 Paging 库有很大不同。此版本提供了增强的功能,并解决了使用 Paging 2 的常见难题。如果您的应用已使用早期版本的 Paging 库,请阅读此页面以了解有关迁移到 Paging 3 的更多信息。

如果 Paging 3 是您在应用中使用的第一个版本的 Paging 库,请参阅 加载和显示分页数据 以获取基本用法信息。

迁移到 Paging 3 的好处

Paging 3 包括以下在早期版本的库中不存在的功能

  • 对 Kotlin 协程和 Flow 的一流支持。
  • 支持使用 RxJava Single 或 Guava ListenableFuture 原语进行异步加载。
  • 内置加载状态和错误信号,用于响应式 UI 设计,包括重试和刷新功能。
  • 对存储库层的改进,包括取消支持和简化的数据源接口。
  • 对表示层的改进,列表分隔符、自定义页面转换以及加载状态标题和页脚。

将您的应用迁移到 Paging 3

要完全迁移到 Paging 3,您必须迁移 Paging 2 的所有三个主要组件

  • DataSource
  • PagedList
  • PagedListAdapter

但是,某些 Paging 3 组件与早期版本的 Paging 向后兼容。特别是,来自 Paging 3 的 PagingSource API 可以作为来自旧版本 LivePagedListBuilderRxPagedListBuilder 的数据源。同样,Pager API 可以使用较旧的 DataSource 对象和 asPagingSourceFactory() 方法。这意味着您有以下迁移选项

  • 您可以将 DataSource 迁移到 PagingSource,但保持 Paging 实现的其余部分不变。
  • 您可以迁移 PagedListPagedListAdapter,但仍使用旧的 DataSource API。
  • 您可以将整个 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 作为最近访问的索引映射正确的初始键。

Kotlin

// 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
}

Java

// Replaces ItemKeyedDataSource.
@Nullable
@Override
String getRefreshKey(state: PagingState<String, User>) {
  Integer anchorPosition = state.anchorPosition;
  if (anchorPosition == null) {
    return null;
  }

  return state.getClosestItemToPosition(anchorPosition);
}

// Replaces PositionalDataSource.
@Nullable
@Override
Integer getRefreshKey(state: PagingState<Integer, User>) {
  return state.anchorPosition;
}

Java

// Replacing ItemKeyedDataSource.
@Nullable
@Override
String getRefreshKey(state: PagingState<String, User>) {
  Integer anchorPosition = state.anchorPosition;
  if (anchorPosition == null) {
    return null;
  }

  return state.getClosestItemToPosition(anchorPosition);
}

// Replacing PositionalDataSource.
@Nullable
@Override
Integer getRefreshKey(state: PagingState<Integer, User>) {
  return state.anchorPosition;
}

列表转换

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

  • DataSource.map()
  • DataSource.mapByPage()
  • DataSource.Factory.map()
  • DataSource.Factory.mapByPage()

在 Paging 3 中,所有转换都作为 PagingData 上的操作符应用。如果使用上述列表中的任何方法来转换分页列表,则必须将转换逻辑从 DataSource 移动到 PagingData,并在使用新的 PagingSource 构造 Pager 时进行。

要了解有关使用 Paging 3 对分页数据应用转换的更多信息,请参阅 转换数据流

PagedList

本节介绍将旧版 Paging 实现迁移到在 Paging 3 中使用 PagerPagingData 所需的所有更改。

PagedListBuilder 类

PagingData 替换了 Paging 2 中现有的 PagedList。要迁移到 PagingData,必须更新以下内容

  • 分页配置已从 PagedList.Config 移动到 PagingConfig
  • LivePagedListBuilderRxPagedListBuilder 已合并到单个 Pager 类中。
  • Pager 通过其 .flow 属性公开一个可观察的 Flow<PagingData>。RxJava 和 LiveData 变体也作为扩展属性可用,可以通过静态方法从 Java 调用,并分别从 paging-rxjava*paging-runtime 模块提供。

Kotlin

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)

Java

// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
Pager<Integer, User> pager = Pager<>(
  new PagingConfig(/* pageSize = */ 20),
  () -> ExamplePagingSource(backend, query));

Flowable<PagingData<User>> flowable = PagingRx.getFlowable(pager);
PagingRx.cachedIn(flowable, viewModelScope);

Java

// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
Pager<Integer, User> pager = Pager<>(
  new PagingConfig(/* pageSize = */ 20),
  () -> ExamplePagingSource(backend, query));

PagingLiveData.cachedIn(PagingLiveData.getLiveData(pager), viewModelScope);

要了解有关使用 Paging 3 设置 PagingData 对象的反应式流的更多信息,请参阅 设置 PagingData 流

分层源的 BoundaryCallback

在 Paging 3 中,RemoteMediator 替换了 PagedList.BoundaryCallback,作为从网络和数据库分页的处理程序。

要了解有关在 Paging 3 中使用 RemoteMediator 从网络和数据库分页的更多信息,请参阅 Android Paging codelab

PagedListAdapter

本节介绍将旧版 Paging 实现迁移到使用 Paging 3 中的 PagingDataAdapterAsyncPagingDataDiffer 类所需的所有更改。

Paging 3 提供 PagingDataAdapter 来处理新的 PagingData 反应式流。否则,PagedListAdapterPagingDataAdapter 具有相同的接口。要从 PagedListAdapter 迁移到 PagingDataAdapter,请将 PagedListAdapter 的实现更改为扩展 PagingDataAdapter

要了解有关 PagingDataAdapter 的更多信息,请参阅 定义 RecyclerView 适配器

AsyncPagedListDiffer

如果当前使用带有 AsyncPagedListDiffer 的自定义 RecyclerView.Adapter 实现,请将实现迁移到改用 Paging 3 中提供的 AsyncPagingDataDiffer

Kotlin

AsyncPagingDataDiffer(diffCallback, listUpdateCallback)

Java

new AsyncPagingDataDiffer(diffCallback, listUpdateCallback);

Java

new AsyncPagingDataDiffer(diffCallback, listUpdateCallback);

其他资源

要了解有关 Paging 库的更多信息,请参阅以下其他资源

Codelabs

示例