迁移到 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。

本页面中的各部分说明了如何在应用程序的各个层级上迁移分页组件。

数据源类

本部分描述了将旧的分页实现迁移到使用PagingSource所需的全部更改。

分页 2 中的PageKeyedDataSourcePositionalDataSourceItemKeyedDataSource都已合并到分页 3 中的PagingSource API 中。所有旧 API 类的加载方法都合并到PagingSource中的单个load()方法中。这减少了代码重复,因为旧 API 类实现中的加载方法之间的许多逻辑通常是相同的。

分页 3 中的所有加载方法参数都被替换为LoadParams密封类,该类包含每个加载类型的子类。如果需要在load()方法中区分加载类型,请检查传入的LoadParams子类:LoadParams.RefreshLoadParams.PrependLoadParams.Append

要了解有关实现PagingSource的更多信息,请参阅定义数据源

刷新键

PagingSource的实现必须定义如何从已加载的分页数据中间恢复刷新。通过实现getRefreshKey()来实现此目的,使用state.anchorPosition作为最近访问的索引来映射正确的初始键。

Kotlin

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

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

Java

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

  return state.getClosestItemToPosition(anchorPosition);
}

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

Java

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

  return state.getClosestItemToPosition(anchorPosition);
}

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

列表转换

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

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

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

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

PagedList

本部分描述了将旧的分页实现迁移到分页 3 中使用PagerPagingData所需的全部更改。

PagedListBuilder 类

PagingData取代了分页 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);

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

分层源的 BoundaryCallback

在分页 3 中,RemoteMediator取代了PagedList.BoundaryCallback,作为从网络和数据库进行分页的处理程序。

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

PagedListAdapter

本部分描述了将旧的分页实现迁移到使用分页 3 中的PagingDataAdapterAsyncPagingDataDiffer类所需的全部更改。

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

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

AsyncPagedListDiffer

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

Kotlin

AsyncPagingDataDiffer(diffCallback, listUpdateCallback)

Java

new AsyncPagingDataDiffer(diffCallback, listUpdateCallback);

Java

new AsyncPagingDataDiffer(diffCallback, listUpdateCallback);

其他资源

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

Codelab

示例