Cómo migrar a Paging 3

Paging 3 es bastante diferente de las versiones anteriores de la biblioteca de paginación. Esta versión proporciona funciones mejoradas y aborda las dificultades comunes del uso de Paging 2. Si tu app ya usa una versión anterior de la biblioteca de paginación, lee esta página para obtener más información sobre la migración a Paging 3.

Si Paging 3 es la primera versión de la biblioteca de paginación que usas en tu app, consulta Cómo cargar y mostrar datos paginados para obtener información básica de uso.

Beneficios de migrar a Paging 3

Paging 3 incluye las siguientes características que no estaban presentes en versiones anteriores de la biblioteca:

  • Compatibilidad de primer nivel con las corrutinas y el flujo de Kotlin
  • Compatibilidad con la carga asíncrona mediante los tipos primitivos Single de RxJava o ListenableFuture de Guava
  • Estado de carga integrado y señales de error para un diseño de IU adaptable, incluida la función de reintento y actualización
  • Mejoras en la capa del repositorio, como la compatibilidad para la cancelación y una interfaz de fuente de datos simplificada
  • Mejoras en la capa de la presentación, los separadores de lista, las transformaciones de páginas personalizadas y el estado de carga de encabezados y pies de página

Cómo migrar tu app a Paging 3

Para realizar la migración completa a Paging 3, debes migrar los tres componentes principales de Paging 2:

  • Clases DataSource
  • PagedList
  • PagedListAdapter

Sin embargo, algunos componentes de Paging 3 son retrocompatibles con versiones anteriores de Paging. En particular, la API de PagingSource de Paging 3 puede ser una fuente de datos para LivePagedListBuilder y RxPagedListBuilder de versiones anteriores. Del mismo modo, la API de Pager puede usar objetos DataSource más antiguos con el método asPagingSourceFactory(). Esto significa que tienes las siguientes opciones de migración:

  • Puedes migrar tu DataSource a PagingSource, pero no modificar el resto de tu implementación de Paging.
  • Puedes migrar PagedList y PagedListAdapter, pero seguir usando la API de DataSource anterior.
  • Puedes migrar toda la implementación de Paging para migrar completamente tu app a Paging 3.

En las secciones de esta página, se explica cómo migrar los componentes de Paging de cada capa de tu app.

Clases DataSource

En esta sección, se describen todos los cambios necesarios para migrar una implementación de Paging más antigua a fin de usar PagingSource.

Los elementos PageKeyedDataSource, PositionalDataSource y ItemKeyedDataSource de Paging 2 se combinan en la API de PagingSource de Paging 3. Los métodos de carga de todas las clases de API anteriores se combinan en un único método load() en PagingSource. Esto reduce la duplicación de código, ya que gran parte de la lógica de los métodos de carga en las implementaciones de las clases de API anteriores suele ser idéntica.

Todos los parámetros de métodos de carga se reemplazan en Paging 3 con una clase sellada LoadParams, que incluye subclases para cada tipo de carga. Si necesitas diferenciar los tipos de carga de tu método load(), verifica qué subclase de LoadParams se pasó en LoadParams.Refresh, LoadParams.Prepend o LoadParams.Append.

Para obtener más información sobre la implementación de PagingSource, consulta Cómo definir una fuente de datos.

Actualiza las claves

Las implementaciones de PagingSource deben definir cómo se reanudan las actualizaciones desde el medio de los datos paginados cargados. Para ello, implementa getRefreshKey() a fin de mapear la clave inicial correcta con state.anchorPosition como el índice al que se accedió más recientemente.

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

Transformaciones de lista

En las versiones anteriores de la biblioteca de Paging, la transformación de los datos paginados se basa en los siguientes métodos:

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

En Paging 3, todas las transformaciones se aplican como operadores en PagingData. Si usas alguno de los métodos de la lista anterior para transformar tu lista paginada, debes mover la lógica de transformación de la DataSource a los PagingData cuando construyas la Pager con tu PagingSource nuevo.

Si quieres obtener más información para aplicar transformaciones a datos paginados con Paging 3, consulta Cómo transformar flujos de datos.

PagedList

En esta sección, se describen todos los cambios necesarios para migrar una implementación de Paging más antigua y usar Pager y PagingData en Paging 3.

Clases PagedListBuilder

PagingData reemplaza a la PagedList existente de Paging 2. Para migrar a PagingData, debes actualizar lo siguiente:

  • La configuración de la paginación se movió de PagedList.Config a PagingConfig.
  • LivePagedListBuilder y RxPagedListBuilder se combinaron en una sola clase Pager.
  • Pager expone un Flow<PagingData> observable con su propiedad .flow. Las variantes de RxJava y LiveData también están disponibles como propiedades de extensión, que se pueden llamar desde Java mediante métodos estáticos y se proporcionan desde los módulos paging-rxjava* y paging-runtime, respectivamente.

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);

Si quieres obtener más información para configurar un flujo reactivo de objetos PagingData con Paging 3, consulta Cómo configurar un flujo de PagingData.

BoundaryCallback para fuentes en capas

En Paging 3, RemoteMediator reemplaza PagedList.BoundaryCallback como un controlador de la paginación desde la red y la base de datos.

Si quieres obtener más información sobre el uso de RemoteMediator para realizar la paginación desde la red y la base de datos en Paging 3, consulta el codelab de paginación de Android.

PagedListAdapter

En esta sección, se describen todos los cambios necesarios para migrar una implementación de Paging más antigua y usar las clases PagingDataAdapter o AsyncPagingDataDiffer en Paging 3.

Paging 3 proporciona PagingDataAdapter para controlar los nuevos flujos de PagingData reactivos. Por lo demás, PagedListAdapter y PagingDataAdapter tienen la misma interfaz. Para migrar de PagedListAdapter a PagingDataAdapter, cambia tu implementación de PagedListAdapter para extender PagingDataAdapter.

Para obtener más información sobre PagingDataAdapter, consulta Cómo definir un adaptador RecyclerView.

AsyncPagedListDiffer

Si actualmente usas una implementación personalizada de RecyclerView.Adapter con AsyncPagedListDiffer, migra tu implementación para usar el AsyncPagingDataDiffer proporcionado en Paging 3 en su lugar:

Kotlin

AsyncPagingDataDiffer(diffCallback, listUpdateCallback)

Java

new AsyncPagingDataDiffer(diffCallback, listUpdateCallback);

Java

new AsyncPagingDataDiffer(diffCallback, listUpdateCallback);

Recursos adicionales

Para obtener más información sobre la biblioteca de Paging, consulta los siguientes recursos adicionales:

Codelabs

Ejemplos