Exibir listas paginadas

Este guia se baseia na Visão geral da Paging Library e descreve como você pode apresentar listas de informações aos usuários na IU do seu app, principalmente quando essas informações mudam.

Conectar a IU ao seu modelo de visualização

Você pode conectar uma instância de LiveData<PagedList> a um PagedListAdapter, conforme mostrado no snippet de código a seguir.

Kotlin

    class ConcertActivity : AppCompatActivity() {
        private val adapter = ConcertAdapter()

        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        private val viewModel: ConcertViewModel by viewModels()

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState);
            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 = new ViewModelProvider(this).get(ConcertViewModel.class);
            viewModel.concertList.observe(this, adapter::submitList);
        }
    }
    

Como as fontes de dados fornecem novas instâncias de PagedList, a atividade envia esses objetos para o adaptador. A implementação PagedListAdapter define como as atualizações são calculadas e processa automaticamente a paginação e o diff da lista. Portanto, seu ViewHolder só precisa ser vinculado a um item específico:

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

O PagedListAdapter processa eventos de carregamento de página usando um objeto PagedList.Callback. À medida que o usuário rola, PagedListAdapter chama PagedList.loadAround() para fornecer dicas ao PagedList sobre quais itens ele deve buscar em DataSource.

Implementar o callback de diferenciação

O exemplo a seguir mostra uma implementação manual de areContentsTheSame(), que compara campos de objeto 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);
        }
    };
    

Como o adaptador inclui sua definição de comparação de itens, ele detecta automaticamente alterações nesses itens quando um novo objeto PagedList é carregado. Como resultado, o adaptador aciona animações de itens eficientes no seu objeto RecyclerView.

Diferenciação usando um tipo de adaptador diferente

Se você optar por não herdar de PagedListAdapter, quando você usa uma biblioteca que fornece seu próprio adaptador, ainda é possível usar a funcionalidade de diferenciação do adaptador da Paging Library ao trabalhar diretamente com um objeto AsyncPagedListDiffer.

Fornecer marcadores na IU

Nos casos em que você quer que sua IU exiba uma lista antes que o app termine de buscar dados, você pode exibir marcadores de itens da lista aos usuários. O PagedList processa esse caso apresentando os dados do item da lista como null até que os dados sejam carregados.

Os marcadores têm os seguintes benefícios:

  • Suporte para barras de rolagem: o PagedList fornece o número de itens da lista para o PagedListAdapter. Essas informações permitem que o adaptador desenhe uma barra de rolagem que transmita o tamanho total da lista. Quando novas páginas são carregadas, a barra de rolagem não pula porque o tamanho da lista não muda.
  • Nenhum ícone de carregamento é necessário: como o tamanho da lista já é conhecido, não há necessidade de avisar os usuários que mais itens estão sendo carregados. Os próprios marcadores transmitem essas informações.

No entanto, antes de acrescentar a compatibilidade com marcadores, lembre-se dos seguintes pré-requisitos:

  • Requer um conjunto de dados contáveis: as instâncias de DataSource da biblioteca de persistência Room podem contar os itens com eficiência. No entanto, caso você esteja usando uma solução de armazenamento local personalizada ou uma arquitetura de dados somente de rede, pode ser caro ou até impossível determinar quantos itens constituem seu conjunto de dados.
  • Necessidade de um adaptador para considerar os itens não carregados: o mecanismo de adaptador ou apresentação usado para preparar a lista para inflação precisa processar itens de lista nulos. Por exemplo, ao vincular dados a um ViewHolder, é necessário fornecer valores padrão para representar dados não carregados.
  • Necessidade de visualização de itens com o mesmo tamanho: se existir a possibilidade de os tamanhos de itens da lista mudarem com base no conteúdo, como em atualizações de redes sociais, o fading cruzado entre os itens não será bom. Nesse caso, recomendamos desativar os marcadores.

Enviar feedback

Compartilhe seus comentários e ideias conosco por meio dos seguintes recursos:

Issue tracker
Informe os problemas para que possamos corrigir os bugs.

Outros recursos

Para saber mais sobre a Paging Library, consulte os recursos a seguir.

Amostras

Codelabs

Vídeos