Cómo visualizar listas paginadas

Esta guía se basa en la descripción general de la biblioteca de paginación y describe cómo puedes presentar listas de información a los usuarios en la IU de tu app, particularmente cuando esta información cambia.

Conecta tu IU al modelo de vista

Puedes conectar una instancia de LiveData<PagedList> a un PagedListAdapter, como se muestra en el siguiente fragmento de código:

Kotlin

    private val adapter = ConcertAdapter()
    private lateinit var viewModel: ConcertViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        viewModel = ViewModelProviders.of(this).get(ConcertViewModel::class.java)
        viewModel.concerts.observe(this, Observer { adapter.submitList(it) })
    }
    

Java

    public class ConcertActivity extends AppCompatActivity {
        private ConcertAdapter adapter = new ConcertAdapter();
        private ConcertViewModel viewModel;

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            viewModel = ViewModelProviders.of(this).get(ConcertViewModel.class);
            viewModel.concertList.observe(this, adapter::submitList);
        }
    }
    

Como las fuentes de datos proporcionan instancias nuevas de PagedList, la actividad envía estos objetos al adaptador. La implementación de PagedListAdapter define cómo se procesan las actualizaciones y maneja automáticamente la paginación y el diffing de listas. Por lo tanto, tu ViewHolder solo necesita vincularse a un elemento proporcionado en particular:

Kotlin

    class ConcertAdapter() :
            PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) {
        override fun onBindViewHolder(holder: ConcertViewHolder, position: Int) {
            val concert: Concert? = getItem(position)

            // Note that "concert" is a placeholder if it's null.
            holder.bindTo(concert)
        }

        companion object {
            private val DIFF_CALLBACK = ... // See Implement the diffing callback section.
        }
    }
    

Java

    public class ConcertAdapter
            extends PagedListAdapter<Concert, ConcertViewHolder> {
        protected ConcertAdapter() {
            super(DIFF_CALLBACK);
        }

        @Override
        public void onBindViewHolder(@NonNull ConcertViewHolder holder,
                int position) {
            Concert concert = getItem(position);

            // Note that "concert" can be null if it's a placeholder.
            holder.bindTo(concert);
        }

        private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK
                = ... // See Implement the diffing callback section.
    }
    

El PagedListAdapter maneja los eventos de carga de página usando un objeto PagedList.Callback. A medida que se desplaza el usuario, el PagedListAdapter llama a PagedList.loadAround() para proporcionar sugerencias a la PagedList subyacente en cuanto a los elementos que debe cargar de DataSource.

Implementa la devolución de llamada de diffing

En el siguiente ejemplo, se muestra una implementación manual de areContentsTheSame(), que compara los campos de objetos relevantes:

Kotlin

    private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Concert>() {
        // The ID property identifies when items are the same.
        override fun areItemsTheSame(oldItem: Concert, newItem: Concert) =
                oldItem.id == newItem.id

        // If you use the "==" operator, make sure that the object implements
        // .equals(). Alternatively, write custom data comparison logic here.
        override fun areContentsTheSame(
                oldItem: Concert, newItem: Concert) = oldItem == newItem
    }
    

Java

    private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<Concert>() {

        @Override
        public boolean areItemsTheSame(Concert oldItem, Concert newItem) {
            // The ID property identifies when items are the same.
            return oldItem.getId() == newItem.getId();
        }

        @Override
        public boolean areContentsTheSame(Concert oldItem, Concert newItem) {
            // Don't use the "==" operator here. Either implement and use .equals(),
            // or write custom data comparison logic here.
            return oldItem.equals(newItem);
        }
    };
    

Debido a que el adaptador incluye tu definición de elementos de comparación, el adaptador detecta automáticamente los cambios a esos elementos cuando se carga un objeto PagedList nuevo. Como resultado, el adaptador activa animaciones de elementos eficaces en el objeto RecyclerView.

Haz diffing usando un tipo de adaptador diferente

Si decides no heredar de PagedListAdapter, por ejemplo, cuando usas una biblioteca que proporciona su propio adaptador, puedes usar la función de diffing del adaptador de la biblioteca de paginación directamente trabajando con un objeto AsyncPagedListDiffer.

Proporciona marcadores de posición en tu IU

En los casos en que desees que la IU muestre una lista antes de que la app haya terminado de cargar datos, puedes mostrar elementos de la lista de marcadores de posición a los usuarios. La PagedList maneja este caso presentando los datos de elementos de la lista como null hasta que se cargan los datos.

Los marcadores de posición tienen los siguientes beneficios:

  • Compatibilidad con barras de desplazamiento: La PagedList proporciona la cantidad de elementos de lista al PagedListAdapter. Esta información permite que el adaptador dibuje una barra de desplazamiento que transmite el tamaño completo de la lista. A medida que se cargan las páginas nuevas, la barra de desplazamiento no salta porque tu lista no cambia de tamaño.
  • No se necesita ningún ícono giratorio de carga: Debido a que el tamaño de la lista ya es conocido, no es necesario avisarles a los usuarios que se están cargando más elementos. Los marcadores de posición transmiten esa información.

Sin embargo, antes de agregar compatibilidad con marcadores de posición, ten en cuenta las siguientes condiciones previas:

  • Se requiere un conjunto de datos contables: Las instancias de DataSource de la biblioteca de Room Persistence pueden contar sus elementos de manera eficiente. Sin embargo, si usas una solución de almacenamiento local personalizada o una arquitectura de datos solo de red, puede ser costoso o incluso imposible determinar cuántos elementos componen tu conjunto de datos.
  • Se requiere un adaptador para tener en cuenta los elementos descargados: El adaptador o mecanismo de presentación que utilizas para preparar la lista para el aumento debe manejar los elementos de la lista nula. Por ejemplo, cuando vinculas datos a un ViewHolder, debes proporcionar valores predeterminados a fin de representar los datos descargados.
  • Se requieren vistas de elementos del mismo tamaño: Si los tamaños de los elementos de la lista pueden cambiar en función de su contenido, como las actualizaciones de las redes sociales, el encadenado entre elementos no se ve bien. Sugerimos inhabilitar los marcadores de posición en este caso.

Envía comentarios

Comparte tus comentarios e ideas con nosotros por medio de estos recursos:

Seguimiento de problemas
Informa los problemas para que podamos solucionar los errores.

Recursos adicionales

Para obtener más información sobre la biblioteca de paginación, consulta los siguientes recursos.

Ejemplos

Codelabs

Videos