Dieser Leitfaden baut auf der Übersicht über die Paging-Bibliothek auf. Hier wird erläutert, wie Sie die Lösung zum Laden von Daten Ihrer Anwendung an die Architekturanforderungen Ihrer Anwendung anpassen können.
Eine beobachtbare Liste erstellen
In der Regel beobachtet der UI-Code ein LiveData<PagedList>
-Objekt (oder, wenn Sie RxJava2 verwenden, ein Flowable<PagedList>
- oder Observable<PagedList>
-Objekt), das sich im ViewModel
Ihrer Anwendung befindet. Dieses beobachtbare Objekt stellt eine Verbindung zwischen der Präsentation und den Inhalten der Listendaten Ihrer App her.
Um eines dieser beobachtbaren PagedList
-Objekte zu erstellen, übergeben Sie eine Instanz von DataSource.Factory
an ein LivePagedListBuilder
- oder RxPagedListBuilder
-Objekt. Ein DataSource
-Objekt lädt Seiten für eine einzelne PagedList
. Die Factory-Klasse erstellt neue Instanzen von PagedList
als Reaktion auf Inhaltsaktualisierungen wie die Entwertung von Datenbanktabellen und Netzwerkaktualisierungen. Die Room Persistence Library kann Ihnen DataSource.Factory
-Objekte zur Verfügung stellen. Sie können aber auch eigene Objekte erstellen.
Das folgende Code-Snippet zeigt, wie Sie mithilfe der Gebäudefunktionen DataSource.Factory
des Raums eine neue Instanz von LiveData<PagedList>
in der Klasse ViewModel
Ihrer App erstellen:
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> }
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(); }
Kotlin
// The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData(pageSize = 50)
Java
// The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = LivePagedListBuilder(myConcertDataSource, /* page size */ 50).build();
Eigene Pagingkonfiguration definieren
Wenn Sie eine LiveData<PagedList>
für komplexere Fälle konfigurieren möchten, können Sie auch eine eigene Seitenkonfiguration definieren. Insbesondere können Sie die folgenden Attribute definieren:
- Seitengröße:Die Anzahl der Elemente auf jeder Seite.
- Prefetch-Entfernung:Unter Berücksichtigung des letzten sichtbaren Elements in der Benutzeroberfläche einer App wird die Anzahl der Elemente, die über dieses letzte Element hinausgehen, angegeben, die die Paging Library im Voraus abrufen sollte. Dieser Wert sollte um ein Vielfaches größer als die Seitengröße sein.
- Platzhaltervorhandensein:Legt fest, ob auf der Benutzeroberfläche Platzhalter für Listenelemente angezeigt werden, die noch nicht vollständig geladen wurden. Informationen zu den Vor- und Nachteilen von Platzhaltern finden Sie unter Platzhalter auf Ihrer Benutzeroberfläche bereitstellen.
Wenn Sie genauer steuern möchten, wann die Paging Library eine Liste aus der Datenbank Ihrer Anwendung lädt, können Sie ein benutzerdefiniertes Executor
-Objekt an LivePagedListBuilder
übergeben, wie im folgenden Code-Snippet gezeigt:
Kotlin
val myPagingConfig = Config( pageSize = 50, prefetchDistance = 150, enablePlaceholders = true ) // The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData( pagingConfig = myPagingConfig, fetchExecutor = myExecutor )
Java
PagedList.Config myPagingConfig = new PagedList.Config.Builder() .setPageSize(50) .setPrefetchDistance(150) .setEnablePlaceholders(true) .build(); // The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig) .setFetchExecutor(myExecutor) .build();
Den richtigen Typ der Datenquelle auswählen
Es ist wichtig, eine Verbindung zu der Datenquelle herzustellen, die die Struktur Ihrer Quelldaten am besten handhabt:
- Verwenden Sie
PageKeyedDataSource
, wenn auf Seiten, die Sie laden, Schlüssel vom Typ „Nächste/vorherige“ eingebettet werden. Wenn Sie beispielsweise Beiträge in sozialen Medien aus dem Netzwerk abrufen, müssen Sie möglicherweise einnextPage
-Token von einem Ladevorgang an einen nachfolgenden Ladevorgang übergeben. - Verwenden Sie
ItemKeyedDataSource
, wenn Sie Daten aus Element N zum Abrufen des Elements N+1 verwenden müssen. Wenn Sie beispielsweise Kommentare mit Unterhaltungsthreads für eine Diskussions-App abrufen, müssen Sie möglicherweise die ID des letzten Kommentars übergeben, um den Inhalt des nächsten Kommentars abzurufen. - Verwenden Sie
PositionalDataSource
, wenn Sie Seiten mit Daten von einem beliebigen Speicherort in Ihrem Datenspeicher abrufen müssen. Diese Klasse unterstützt das Anfordern eines Satzes von Datenelementen ab dem von Ihnen ausgewählten Speicherort. Die Anfrage könnte beispielsweise die 50 Datenelemente zurückgeben, die mit Position 1500 beginnen.
Benachrichtigen, wenn Daten ungültig sind
Wenn Sie die Paging Library verwenden, muss die Datenschicht die anderen Ebenen der Anwendung benachrichtigen, wenn eine Tabelle oder Zeile veraltet ist. Rufen Sie dazu invalidate()
aus der Klasse DataSource
auf, die Sie für Ihre Anwendung ausgewählt haben.
Eigene Datenquellen erstellen
Wenn Sie eine benutzerdefinierte lokale Datenlösung verwenden oder Daten direkt aus einem Netzwerk laden, können Sie eine der abgeleiteten DataSource
-Klassen implementieren. Das folgende Code-Snippet zeigt eine Datenquelle, die auf der Startzeit eines bestimmten Konzerts basiert:
Kotlin
class ConcertTimeDataSource() : ItemKeyedDataSource<Date, Concert>() { override fun getKey(item: Concert) = item.startTime override fun loadInitial( params: LoadInitialParams<Date>, callback: LoadInitialCallback<Concert>) { val items = fetchItems(params.requestedInitialKey, params.requestedLoadSize) callback.onResult(items) } override fun loadAfter( params: LoadParams<Date>, callback: LoadCallback<Concert>) { val items = fetchItemsAfter( date = params.key, limit = params.requestedLoadSize) callback.onResult(items) } }
Java
public class ConcertTimeDataSource extends ItemKeyedDataSource<Date, Concert> { @NonNull @Override public Date getKey(@NonNull Concert item) { return item.getStartTime(); } @Override public void loadInitial(@NonNull LoadInitialParams<Date> params, @NonNull LoadInitialCallback<Concert> callback) { List<Concert> items = fetchItems(params.key, params.requestedLoadSize); callback.onResult(items); } @Override public void loadAfter(@NonNull LoadParams<Date> params, @NonNull LoadCallback<Concert> callback) { List<Concert> items = fetchItemsAfter(params.key, params.requestedLoadSize); callback.onResult(items); }
Sie können diese benutzerdefinierten Daten dann in PagedList
-Objekte laden, indem Sie eine konkrete abgeleitete Klasse von DataSource.Factory
erstellen. Das folgende Code-Snippet zeigt, wie neue Instanzen der benutzerdefinierten Datenquelle generiert werden, die im vorherigen Code-Snippet definiert wurde:
Kotlin
class ConcertTimeDataSourceFactory : DataSource.Factory<Date, Concert>() { val sourceLiveData = MutableLiveData<ConcertTimeDataSource>() var latestSource: ConcertDataSource? override fun create(): DataSource<Date, Concert> { latestSource = ConcertTimeDataSource() sourceLiveData.postValue(latestSource) return latestSource } }
Java
public class ConcertTimeDataSourceFactory extends DataSource.Factory<Date, Concert> { private MutableLiveData<ConcertTimeDataSource> sourceLiveData = new MutableLiveData<>(); private ConcertDataSource latestSource; @Override public DataSource<Date, Concert> create() { latestSource = new ConcertTimeDataSource(); sourceLiveData.postValue(latestSource); return latestSource; } }
Überdenken, wie Inhaltsaktualisierungen funktionieren
Berücksichtigen Sie beim Erstellen von beobachtbaren PagedList
-Objekten, wie Inhaltsaktualisierungen funktionieren. Wenn Sie Daten direkt aus einer Raumdatenbank laden, werden Aktualisierungen automatisch an die Benutzeroberfläche Ihrer App übertragen.
Wenn Sie eine Netzwerk-API mit Seiteninformationen verwenden, erfolgt in der Regel eine Nutzerinteraktion wie „Zum Aktualisieren wischen“, um die zuletzt verwendete DataSource
zu ungültig zu machen. Anschließend fordern Sie eine neue Instanz dieser Datenquelle an. Das folgende Code-Snippet veranschaulicht dieses Verhalten:
Kotlin
class ConcertActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // ... concertTimeViewModel.refreshState.observe(this, Observer { // Shows one possible way of triggering a refresh operation. swipeRefreshLayout.isRefreshing = it == MyNetworkState.LOADING }) swipeRefreshLayout.setOnRefreshListener { concertTimeViewModel.invalidateDataSource() } } } class ConcertTimeViewModel(firstConcertStartTime: Date) : ViewModel() { val dataSourceFactory = ConcertTimeDataSourceFactory(firstConcertStartTime) val concertList: LiveData<PagedList<Concert>> = dataSourceFactory.toLiveData( pageSize = 50, fetchExecutor = myExecutor ) fun invalidateDataSource() = dataSourceFactory.sourceLiveData.value?.invalidate() }
Java
public class ConcertActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { // ... viewModel.getRefreshState() .observe(this, new Observer<NetworkState>() { // Shows one possible way of triggering a refresh operation. @Override public void onChanged(@Nullable MyNetworkState networkState) { swipeRefreshLayout.isRefreshing = networkState == MyNetworkState.LOADING; } }; swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshListener() { @Override public void onRefresh() { viewModel.invalidateDataSource(); } }); } } public class ConcertTimeViewModel extends ViewModel { private LiveData<PagedList<Concert>> concertList; private DataSource<Date, Concert> mostRecentDataSource; public ConcertTimeViewModel(Date firstConcertStartTime) { ConcertTimeDataSourceFactory dataSourceFactory = new ConcertTimeDataSourceFactory(firstConcertStartTime); mostRecentDataSource = dataSourceFactory.create(); concertList = new LivePagedListBuilder<>(dataSourceFactory, 50) .setFetchExecutor(myExecutor) .build(); } public void invalidateDataSource() { mostRecentDataSource.invalidate(); } }
Datenzuordnung bereitstellen
Die Auslagerungsbibliothek unterstützt element- und seitenbasierte Transformationen von Elementen, die von einem DataSource
geladen werden.
Im folgenden Code-Snippet wird eine Kombination aus Konzertname und Konzertdatum einem einzelnen String zugeordnet, der sowohl den Namen als auch das Datum enthält:
Kotlin
class ConcertViewModel : ViewModel() { val concertDescriptions : LiveData<PagedList<String>> init { val concerts = database.allConcertsFactory() .map { "${it.name} - ${it.date}" } .toLiveData(pageSize = 50) } }
Java
public class ConcertViewModel extends ViewModel { private LiveData<PagedList<String>> concertDescriptions; public ConcertViewModel(MyDatabase database) { DataSource.Factory<Integer, Concert> factory = database.allConcertsFactory().map(concert -> concert.getName() + "-" + concert.getDate()); concertDescriptions = new LivePagedListBuilder<>( factory, /* page size */ 50).build(); } }
Dies kann nützlich sein, wenn Sie Elemente nach dem Laden zusammenfassen, konvertieren oder vorbereiten möchten. Da diese Arbeit mit dem Abruf-Executor ausgeführt wird, können möglicherweise kostspielige Aufgaben wie das Lesen von der Festplatte oder das Abfragen einer separaten Datenbank ausgeführt werden.
Feedback geben
Teilen Sie uns Ihr Feedback und Ihre Ideen über diese Ressourcen mit:
- Problemverfolgung
- Melden Sie Probleme, damit wir sie beheben können.
Weitere Informationen
Weitere Informationen zur Paging Library finden Sie in den folgenden Ressourcen.
Produktproben
Codelabs
Videos
- Android Jetpack: unendliche Listen mit RecyclerView und Paging verwalten (Google I/O 2018)
- Android Jetpack: Paging
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Migration zu Paging 3
- Paging 2-Bibliothek – Übersicht
- Listen mit Seitennummern anzeigen