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

    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 as fontes de dados fornecem novas instâncias de PagedList, a atividade envia esses objetos para o adaptador. A implementação de PagedListAdapter define como as atualizações são computadas e processa automaticamente a paginação e a diferenciação de listas. Portanto, o ViewHolder só precisa se vincular a um item específico fornecido:

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 os eventos de carregamento de página usando um objeto PagedList.Callback. À medida que o usuário rola a página, o PagedListAdapter chama PagedList.loadAround() para fornecer dicas para a PagedList subjacente sobre quais itens ele precisa buscar da DataSource.

Implementar o callback de diferenciação

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

Como seu adaptador inclui sua definição de comparação de itens, o adaptador detecta automaticamente mudanças 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, como em casos em que é usada uma biblioteca que fornece o próprio adaptador, ainda será possível usar a função de diferenciação do adaptador da Paging Library, trabalhando 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 dos itens da lista como null até que os dados sejam carregados.

Os marcadores têm os seguintes benefícios:

  • Compatibilidade com barras de rolagem: a 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:

  • Necessidade de um conjunto de dados contável: as instâncias de DataSource da Room Persistence Library podem contar os itens de forma eficiente. 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 recursos a seguir:

Rastreador de problemas
Informe os problemas para que possamos corrigir os bugs.

Outros recursos

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

Exemplos

Codelabs

Vídeos