Paging 2-Bibliothek – Übersicht Teil von Android Jetpack

Mit der Paging Library können Sie kleine Datenblöcke gleichzeitig laden und anzeigen. Das Laden von Teildaten bei Bedarf reduziert die Nutzung von Netzwerkbandbreite und System Ressourcen.

Dieser Leitfaden enthält mehrere konzeptionelle Beispiele der Bibliothek sowie eine einen Überblick über die Funktionsweise. Um vollständige Beispiele dafür anzuzeigen, wie diese Bibliothek testen Sie das Codelab und Beispiele aus den zusätzlichen Ressourcen.

Einrichten

Fügen Sie Folgendes hinzu, um Paging-Komponenten in Ihre Android-App zu importieren zur Datei build.gradle Ihrer Anwendung hinzufügen:

Cool

dependencies {
  def paging_version = "2.1.2"

  implementation "androidx.paging:paging-runtime:$paging_version" // For Kotlin use paging-runtime-ktx

  // alternatively - without Android dependencies for testing
  testImplementation "androidx.paging:paging-common:$paging_version" // For Kotlin use paging-common-ktx

  // optional - RxJava support
  implementation "androidx.paging:paging-rxjava2:$paging_version" // For Kotlin use paging-rxjava2-ktx
}

Kotlin

dependencies {
  val paging_version = "2.1.2"

  implementation("androidx.paging:paging-runtime:$paging_version") // For Kotlin use paging-runtime-ktx

  // alternatively - without Android dependencies for testing
  testImplementation("androidx.paging:paging-common:$paging_version") // For Kotlin use paging-common-ktx

  // optional - RxJava support
  implementation("androidx.paging:paging-rxjava2:$paging_version") // For Kotlin use paging-rxjava2-ktx
}

Bibliotheksarchitektur

In diesem Abschnitt werden die Hauptkomponenten der Paging-Bibliothek beschrieben und dargestellt.

Seitenliste

Die Hauptkomponente der Paging Library Klasse PagedList, die geladen wird Teile Ihrer App-Daten oder Seiten. Da mehr Daten benötigt werden, das vorhandene PagedList-Objekt aufgerufen wird. Wenn sich geladene Daten ändern, wird ein neuer Instanz von PagedList an den Inhaber der beobachtbaren Daten von einer LiveData- oder RxJava2-basiertes Objekt. Als PagedList-Objekte generiert werden, werden die Inhalte in der Benutzeroberfläche Ihrer App präsentiert. Lebenszyklen.

Im folgenden Code-Snippet sehen Sie, wie Sie das Ansichtsmodell Ihrer App so konfigurieren können, Daten mit dem Inhaber LiveData von PagedList-Objekten laden und präsentieren:

Kotlin

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
    val concertList: LiveData<PagedList<Concert>> =
            concertDao.concertsByDate().toLiveData(pageSize = 50)
}

Java

public class ConcertViewModel extends ViewModel {
    private ConcertDao concertDao;
    public final LiveData<PagedList<Concert>> concertList;

    // Creates a PagedList object with 50 items per page.
    public ConcertViewModel(ConcertDao concertDao) {
        this.concertDao = concertDao;
        concertList = new LivePagedListBuilder<>(
                concertDao.concertsByDate(), 50).build();
    }
}

Daten

Jede Instanz von PagedList wird geladen. eine aktuelle Übersicht der Daten Ihrer App aus der zugehörigen DataSource-Objekt. Datenflüsse aus dem Back-End oder der Datenbank Ihrer App in das PagedList-Objekt.

Im folgenden Beispiel wird die Funktion Raumpersistenz Bibliothek zum Organisieren der App-Daten verwenden. Ihre Daten auf andere Weise speichern möchten, können Sie auch Ihre eigenen Daten bereitstellen. Source Factory erstellt werden.

Kotlin

@Dao
interface ConcertDao {
    // The Int type parameter tells Room to use a PositionalDataSource object.
    @Query("SELECT * FROM concerts ORDER BY date DESC")
    fun concertsByDate(): DataSource.Factory<Int, Concert>
}

Java

@Dao
public interface ConcertDao {
    // The Integer type parameter tells Room to use a
    // PositionalDataSource object.
    @Query("SELECT * FROM concerts ORDER BY date DESC")
    DataSource.Factory<Integer, Concert> concertsByDate();
}

Weitere Informationen zum Laden von Daten in PagedList-Objekte findest du in der Weitere Informationen zum Laden von Seitendaten

UI

Die Klasse PagedList funktioniert mit einem PagedListAdapter, um Elemente in eine RecyclerView Diese Klassen arbeiten zusammen, um Inhalte abzurufen und anzuzeigen, während sie geladen werden. und animierte Inhalte ändern.

Weitere Informationen finden Sie unter Seitenumbruch Listen enthalten.

Verschiedene Datenarchitekturen unterstützen

Die Paging Library unterstützt die folgenden Datenarchitekturen:

  • Sie werden nur von einem Backend-Server bereitgestellt.
  • Wird nur in einer Datenbank auf dem Gerät gespeichert.
  • Eine Kombination aus den anderen Quellen, wobei die Datenbank auf dem Gerät als Cache verwendet wird.

Abbildung 1 zeigt den Datenfluss in jedem dieser Architekturszenarien. In Bei einer reinen Netzwerk- oder Datenbanklösung fließen die Daten direkt das UI-Modell Ihrer App. Bei einem kombinierten Ansatz fließen Daten von Ihrem Back-End-Server, in eine Datenbank auf dem Gerät und dann in das UI-Modell Ihrer App. Hin und wieder gehen am Endpunkt jedes Datenflusses keine Daten zum Laden aus. und fordert dann mehr Daten von der Komponente an, die die Daten bereitgestellt hat. Wenn beispielsweise eine Datenbank auf dem Gerät keine Daten mehr hat, fordert sie mehr Daten an. vom Server.

<ph type="x-smartling-placeholder">
</ph> Diagramme von Datenflüssen
<ph type="x-smartling-placeholder">
</ph> Abbildung 1: Wie Daten durch die einzelnen Architekturen fließen, Paging Library wird unterstützt

Im weiteren Verlauf dieses Abschnitts finden Sie Empfehlungen für die Data Flow-Anwendungsfall.

Nur Netzwerk

Um Daten von einem Back-End-Server anzuzeigen, verwenden Sie die synchrone Version des Retrofit API zum Laden Informationen in Ihre eigene DataSource .

Nur Datenbank

RecyclerView einrichten die lokale Speicherung beobachten, vorzugsweise mit der Funktion Raumpersistenz Mediathek. Auf diese Weise, wenn Daten in die Datenbank Ihrer App eingefügt oder geändert haben, werden diese Änderungen in der RecyclerView wider, in der diese Daten angezeigt werden.

Netzwerk und Datenbank

Nachdem Sie begonnen haben, die Datenbank zu beobachten, können Sie darauf warten, wann die Datenbank Datenbank keine Daten mehr hat, PagedList.BoundaryCallback Sie können dann weitere Elemente aus Ihrem Netzwerk abrufen und diese in den Datenbank. Wenn Ihre Benutzeroberfläche die Datenbank beobachtet, ist das alles, was Sie tun müssen.

Netzwerkfehler beheben

Wenn Sie die angezeigten Daten mithilfe eines Netzwerks abrufen oder durch Paging Library, ist es wichtig, das Netzwerk nicht als „Verfügbar“ oder „nicht verfügbar“ da viele Verbindungen unterbrochen sind. unzuverlässig:

  • Ein bestimmter Server kann unter Umständen nicht auf eine Netzwerkanfrage antworten.
  • Das Gerät ist möglicherweise mit einem langsamen oder schwachen Netzwerk verbunden.

Stattdessen sollte Ihre Anwendung jede Anfrage auf Fehler prüfen und eine Wiederherstellung wenn das Netzwerk nicht verfügbar ist. Beispiel: können Sie eine Wiederholung Schaltfläche, über die Nutzer auswählen können, ob der Schritt nicht funktioniert. Tritt beim Datenpaging ein Fehler auf, versuchen Sie es am besten, die Paginganfragen automatisch verarbeiten.

Vorhandene App aktualisieren

Wenn Ihre App bereits Daten aus einer Datenbank oder einer Back-End-Quelle nutzt, ist es ein direktes Upgrade auf die Funktionen der Paging Library möglich ist. In diesem Abschnitt wird beschrieben, wie Sie eine App mit einem gängigen bestehenden Design aktualisieren.

Benutzerdefinierte Paging-Lösungen

Wenn Sie benutzerdefinierte Funktionen zum Laden kleiner Teilmengen von Daten aus dem Datenquelle enthalten, können Sie diese Logik durch die Klasse PagedList. Instanzen von PagedList bieten integrierte Verbindungen zu gängigen Datenquellen. Diese Instanzen bieten auch Adapter für RecyclerView-Objekte, die die Sie in die Benutzeroberfläche Ihrer App einbinden können.

Daten, die mithilfe von Listen statt Seiten geladen werden

Wenn Sie eine Liste im Speicher als Sicherungsdatenstruktur für die sollten Sie Datenaktualisierungen mit einem Klasse PagedList, wenn die Nummer von Elementen in der Liste werden kann. Instanzen von PagedList können Folgendes verwenden: LiveData<PagedList> oder Observable<List>, um Datenaktualisierungen an die Benutzeroberfläche deiner App zu übergeben und so die Ladezeiten zu minimieren und Arbeitsspeichernutzung. Noch besser: Als Ersatz für List PagedList-Objekts in Ihrer App erfordert keine Änderungen an Ihrem die UI-Struktur oder die Logik der Datenaktualisierung der App.

Datencursor über CursorAdapter mit einer Listenansicht verknüpfen

Deine App verwendet möglicherweise einen CursorAdapter um Daten aus einer Cursor mit einem ListView In diesem Fall müssen Sie von einem ListView zu einem RecyclerView als Ihr App-Liste und ersetzen Sie dann Cursor mit entweder Room oder PositionalDataSource, je nachdem, ob Instanzen von Cursor auf SQLite-Datenbank.

In einigen Situationen, z. B. bei der Arbeit mit Instanzen Spinner – Sie stellen nur den Adapter bereit selbst. Eine Bibliothek nimmt dann die Daten, die in diesen Adapter geladen werden, zeigt die Daten für Sie an. Ändern Sie in diesen Fällen den Typ des die Daten des Adapters LiveData<PagedList>, dann Zeilenumbruch diese Liste in einem ArrayAdapter-Objekt bevor Sie versuchen, die Elemente auf einer Benutzeroberfläche von einer Bibliotheksklasse in die Luft zu treiben.

Inhalte mit AsyncListUtil asynchron laden

Wenn Sie AsyncListUtil-Objekte in Gruppen von Informationen asynchron laden und anzeigen können, können Sie mit der Paging Library einfacher laden:

  • Ihre Daten müssen nicht positionell sein. Mit der Paging Library können Sie Daten mithilfe von Schlüsseln, die vom Netzwerk bereitgestellt werden, direkt aus Ihrem Back-End abzurufen.
  • Ihre Daten können unendlich groß sein. Mit der Paging Library können Sie auf Seiten verteilt werden, bis keine Daten mehr vorhanden sind.
  • Sie können Ihre Daten besser beobachten. Über die Paging-Bibliothek können Daten, die ViewModel Ihrer App in einer beobachtbaren Datenstruktur gespeichert wird.

Datenbankbeispiele

Die folgenden Code-Snippets zeigen mehrere Möglichkeiten, wie alle Teile zusammenarbeiten können.

Beobachten von Page-Daten mit LiveData

Das folgende Code-Snippet zeigt, wie alle Teile zusammenwirken. Als Konzert Ereignisse in der Datenbank hinzugefügt, entfernt oder geändert werden, wird der Inhalt der Seite RecyclerView ist automatisch und effizient aktualisiert:

Kotlin

@Dao
interface ConcertDao {
    // The Int type parameter tells Room to use a PositionalDataSource
    // object, with position-based loading under the hood.
    @Query("SELECT * FROM concerts ORDER BY date DESC")
    fun concertsByDate(): DataSource.Factory<Int, Concert>
}

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
    val concertList: LiveData<PagedList<Concert>> =
            concertDao.concertsByDate().toLiveData(pageSize = 50)
}

class ConcertActivity : AppCompatActivity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        val viewModel: ConcertViewModel by viewModels()
        val recyclerView = findViewById(R.id.concert_list)
        val adapter = ConcertAdapter()
        viewModel.concertList.observe(this, PagedList(adapter::submitList))
        recyclerView.setAdapter(adapter)
    }
}

class ConcertAdapter() :
        PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) {
    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 = object :
                DiffUtil.ItemCallback<Concert>() {
            // Concert details may have changed if reloaded from the database,
            // but ID is fixed.
            override fun areItemsTheSame(oldConcert: Concert,
                    newConcert: Concert) = oldConcert.id == newConcert.id

            override fun areContentsTheSame(oldConcert: Concert,
                    newConcert: Concert) = oldConcert == newConcert
        }
    }
}

Java

@Dao
public interface ConcertDao {
    // The Integer type parameter tells Room to use a PositionalDataSource
    // object, with position-based loading under the hood.
    @Query("SELECT * FROM concerts ORDER BY date DESC")
    DataSource.Factory<Integer, Concert> concertsByDate();
}

public class ConcertViewModel extends ViewModel {
    private ConcertDao concertDao;
    public final LiveData<PagedList<Concert>> concertList;

    public ConcertViewModel(ConcertDao concertDao) {
        this.concertDao = concertDao;
        concertList = new LivePagedListBuilder<>(
            concertDao.concertsByDate(), /* page size */ 50).build();
    }
}

public class ConcertActivity extends AppCompatActivity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ConcertViewModel viewModel =
                new ViewModelProvider(this).get(ConcertViewModel.class);
        RecyclerView recyclerView = findViewById(R.id.concert_list);
        ConcertAdapter adapter = new ConcertAdapter();
        viewModel.concertList.observe(this, adapter::submitList);
        recyclerView.setAdapter(adapter);
    }
}

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);
        if (concert != null) {
            holder.bindTo(concert);
        } else {
            // Null defines a placeholder item - PagedListAdapter automatically
            // invalidates this row when the actual object is loaded from the
            // database.
            holder.clear();
        }
    }

    private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<Concert>() {
        // Concert details may have changed if reloaded from the database,
        // but ID is fixed.
        @Override
        public boolean areItemsTheSame(Concert oldConcert, Concert newConcert) {
            return oldConcert.getId() == newConcert.getId();
        }

        @Override
        public boolean areContentsTheSame(Concert oldConcert,
                Concert newConcert) {
            return oldConcert.equals(newConcert);
        }
    };
}

Paged-Daten mit RxJava2 beobachten

Wenn Sie lieber RxJava2 anstelle von LiveData können Sie stattdessen Erstellen Sie ein Observable- oder Flowable-Objekt:

Kotlin

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
    val concertList: Observable<PagedList<Concert>> =
            concertDao.concertsByDate().toObservable(pageSize = 50)
}

Java

public class ConcertViewModel extends ViewModel {
    private ConcertDao concertDao;
    public final Observable<PagedList<Concert>> concertList;

    public ConcertViewModel(ConcertDao concertDao) {
        this.concertDao = concertDao;

        concertList = new RxPagedListBuilder<>(
                concertDao.concertsByDate(), /* page size */ 50)
                        .buildObservable();
    }
}

Sie können die Beobachtung der Daten dann starten und beenden, indem Sie den folgenden Code verwenden: snippet:

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

    private val disposable = CompositeDisposable()

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val recyclerView = findViewById(R.id.concert_list)
        recyclerView.setAdapter(adapter)
    }

    override fun onStart() {
        super.onStart()
        disposable.add(viewModel.concertList
                .subscribe(adapter::submitList)))
    }

    override fun onStop() {
        super.onStop()
        disposable.clear()
    }
}

Java

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

    private CompositeDisposable disposable = new CompositeDisposable();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        RecyclerView recyclerView = findViewById(R.id.concert_list);

        viewModel = new ViewModelProvider(this).get(ConcertViewModel.class);
        recyclerView.setAdapter(adapter);
    }

    @Override
    protected void onStart() {
        super.onStart();
        disposable.add(viewModel.concertList
                .subscribe(adapter.submitList(flowableList)
        ));
    }

    @Override
    protected void onStop() {
        super.onStop();
        disposable.clear();
    }
}

Der Code für ConcertDao und ConcertAdapter ist für einen RxJava2-basiert so wie für ein Unternehmen LiveData-basierte Lösung.

Feedback geben

Wir freuen uns über dein Feedback und deine Ideen:

Problemverfolgung
Melde Probleme, damit wir sie beheben können.

Weitere Informationen

Weitere Informationen zur Paging Library finden Sie in der in den folgenden Ressourcen.

Produktproben

Codelabs

Videos