Visualizza elenchi impaginati

Questa guida si basa sulla panoramica sulla libreria di pacchetti e descrive come presentare elenchi di informazioni agli utenti nella UI dell'app, in particolare quando queste informazioni cambiano.

Collega la tua UI al modello di visualizzazione

Puoi connettere un'istanza di LiveData<PagedList> a PagedListAdapter, come mostrato nel seguente snippet di codice:

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

Man mano che le origini dati forniscono nuove istanze di PagedList, l'attività invia questi oggetti all'adattatore. L'implementazione di PagedListAdapter definisce il modo in cui vengono calcolati gli aggiornamenti e gestisce automaticamente il impaginazione e la differenziazione degli elenchi. Pertanto, ViewHolder deve essere associato solo a un determinato elemento fornito:

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

L'elemento PagedListAdapter gestisce gli eventi di caricamento pagina utilizzando un oggetto PagedList.Callback. Mentre l'utente scorre, PagedListAdapter chiama PagedList.loadAround() per fornire suggerimenti all'elemento PagedList sottostante su quali elementi deve recuperare da DataSource.

Implementa il callback diverso

Il seguente esempio mostra un'implementazione manuale di areContentsTheSame(), che confronta i campi oggetto pertinenti:

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

Poiché l'adattatore include la tua definizione di confronto degli elementi, rileva automaticamente le modifiche a questi elementi quando viene caricato un nuovo oggetto PagedList. Di conseguenza, l'adattatore attiva animazioni efficaci degli elementi all'interno dell'oggetto RecyclerView.

Differenza con l'utilizzo di un tipo di adattatore diverso

Se scegli di non ereditare da PagedListAdapter, ad esempio quando utilizzi una libreria che fornisce il proprio adattatore, puoi comunque utilizzare la funzionalità di differenziazione dell'adattatore della Raccolta di pagine lavorando direttamente con un oggetto AsyncPagedListDiffer.

Fornire segnaposto nell'interfaccia utente

Se vuoi che la UI mostri un elenco prima che l'app abbia terminato il recupero dei dati, puoi mostrare agli utenti le voci dell'elenco segnaposto. L'elemento PagedList gestisce questo caso presentando i dati degli elementi dell'elenco come null fino al caricamento dei dati.

I segnaposto offrono i seguenti vantaggi:

  • Supporto per barre di scorrimento: PagedList fornisce il numero di elementi dell'elenco a PagedListAdapter. Queste informazioni consentono all'adattatore di tracciare una barra di scorrimento che mostra la dimensione intera dell'elenco. Quando vengono caricate nuove pagine, la barra di scorrimento non salta perché la dimensione dell'elenco non cambia.
  • Nessuna icona di caricamento necessaria: poiché la dimensione dell'elenco è già nota, non è necessario avvisare gli utenti che è in corso il caricamento di altri elementi. I segnaposto stessi trasmettono queste informazioni.

Tuttavia, prima di aggiungere il supporto per i segnaposto, tieni presente le seguenti condizioni preliminari:

  • Richiede un set di dati conteggiabile: le istanze di DataSource della libreria di persistenza delle stanze possono conteggiare gli elementi in modo efficiente. Tuttavia, se utilizzi una soluzione di archiviazione locale personalizzata o un'architettura dei dati di sola rete, potrebbe essere costoso, o addirittura impossibile, determinare quanti elementi compongono il set di dati.
  • Richiede l'adattatore per tenere conto degli elementi non caricati: l'adattatore o il meccanismo di presentazione che utilizzi per preparare l'elenco per l'inflazione deve gestire elementi dell'elenco nulli. Ad esempio, quando associ i dati a una ViewHolder, devi fornire valori predefiniti per rappresentare i dati non caricati.
  • Richiede visualizzazioni degli elementi della stessa dimensione: se le dimensioni degli elementi dell'elenco possono cambiare in base ai relativi contenuti, ad esempio gli aggiornamenti dei social network, la dissolvenza incrociata tra gli elementi non sembra corretta. In questo caso consigliamo vivamente di disabilitare i segnaposto.

Fornisci feedback

Condividi il tuo feedback e le tue idee con noi attraverso queste risorse:

Issue Tracker
Segnala i problemi per consentirci di correggerli.

Risorse aggiuntive

Per scoprire di più sulla libreria di paging, consulta le risorse seguenti.

Samples

Codelab

Video