Die Paging-Bibliothek verfolgt den Status von Ladeanforderungen für Seitendaten und stellt
mithilfe der Klasse LoadState
.
Ihre App kann einen Listener mit der
PagingDataAdapter
bis
Informationen zum aktuellen Status abrufen
und die Benutzeroberfläche entsprechend aktualisieren. Diese
Status werden vom Adapter bereitgestellt, da sie mit der Benutzeroberfläche synchron sind.
Das bedeutet, dass Ihr Listener nach Abschluss des Seitenaufbaus Updates erhält.
auf die Benutzeroberfläche angewendet.
Für jedes Feld wird ein separates LoadState
-Signal bereitgestellt.
LoadType
und Datenquellentyp
(entweder PagingSource
oder
RemoteMediator
. Die
CombinedLoadStates
.
-Objekt, das vom Listener bereitgestellt wird, liefert Informationen zum Ladestatus
aus all diesen Signalen. Anhand dieser detaillierten Informationen können Sie die
angemessene Ladeindikatoren für Ihre Nutzer.
Status werden geladen
Die Paging-Bibliothek stellt den Ladestatus zur Verwendung in der Benutzeroberfläche über die
LoadState
-Objekt. LoadState
-Objekte können eine von drei Formen annehmen, je nachdem,
Aktueller Ladestatus:
- Wenn kein aktiver Ladevorgang und kein Fehler vorhanden ist, ist
LoadState
einLoadState.NotLoading
-Objekt enthält. Diese abgeleitete Klasse enthält auch denendOfPaginationReached
, der angibt, ob das Ende der Paginierung erreicht wurde. - Wenn es einen aktiven Ladevorgang gibt, ist
LoadState
einLoadState.Loading
-Objekt enthält. - Falls ein Fehler vorliegt, ist
LoadState
ein ObjektLoadState.Error
.
Es gibt zwei Möglichkeiten, LoadState
in Ihrer UI zu verwenden: mithilfe eines Listeners oder mithilfe eines
Listenadapter verwenden, um den Ladestatus direkt im
RecyclerView
Liste.
Mit einem Listener auf den Ladestatus zugreifen
Um den Ladestatus für den allgemeinen Gebrauch in Ihrer Benutzeroberfläche abzurufen, verwenden Sie die Methode
loadStateFlow
oder die
addLoadStateListener()
von PagingDataAdapter
bereitgestellt. Diese Mechanismen ermöglichen den Zugriff auf
Ein CombinedLoadStates
-Objekt, das Informationen zum LoadState
enthält
für jeden Ladetyp.
Im folgenden Beispiel zeigt PagingDataAdapter
eine andere UI an
Komponenten abhängig vom aktuellen Status des Aktualisierungsladevorgangs:
Kotlin
// Activities can use lifecycleScope directly, but Fragments should instead use // viewLifecycleOwner.lifecycleScope. lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> progressBar.isVisible = loadStates.refresh is LoadState.Loading retry.isVisible = loadState.refresh !is LoadState.Loading errorMsg.isVisible = loadState.refresh is LoadState.Error } }
Java
pagingAdapter.addLoadStateListener(loadStates -> { progressBar.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.VISIBLE : View.GONE); retry.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.GONE : View.VISIBLE); errorMsg.setVisibility(loadStates.refresh instanceof LoadState.Error ? View.VISIBLE : View.GONE); });
Java
pagingAdapter.addLoadStateListener(loadStates -> { progressBar.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.VISIBLE : View.GONE); retry.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.GONE : View.VISIBLE); errorMsg.setVisibility(loadStates.refresh instanceof LoadState.Error ? View.VISIBLE : View.GONE); });
Weitere Informationen zu CombinedLoadStates
finden Sie unter Auf zusätzliche Ladevorgänge zugreifen
Informationen zum Bundesstaat.
Ladestatus mit einem Adapter darstellen
Die Paging-Bibliothek bietet einen weiteren Listenadapter namens
LoadStateAdapter
für den
wird der Ladezustand direkt in der angezeigten Liste der Seiten
Daten. Dieser Adapter bietet Zugriff auf den aktuellen Ladestatus der Liste, der
die Sie an einen benutzerdefinierten Ansichts-Inhaber übergeben können,
der die Informationen anzeigt.
Erstellen Sie zunächst eine Ansichtshalteklasse, die Verweise auf die Lade- und Fehler
Ansichten auf Ihrem Bildschirm. Erstellen Sie eine bind()
-Funktion, die LoadState
als
. Diese Funktion sollte die Ansicht der Ansicht je nach Auslastung ein- oder ausschalten
state-Parameter an:
Kotlin
class LoadStateViewHolder( parent: ViewGroup, retry: () -> Unit ) : RecyclerView.ViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.load_state_item, parent, false) ) { private val binding = LoadStateItemBinding.bind(itemView) private val progressBar: ProgressBar = binding.progressBar private val errorMsg: TextView = binding.errorMsg private val retry: Button = binding.retryButton .also { it.setOnClickListener { retry() } } fun bind(loadState: LoadState) { if (loadState is LoadState.Error) { errorMsg.text = loadState.error.localizedMessage } progressBar.isVisible = loadState is LoadState.Loading retry.isVisible = loadState is LoadState.Error errorMsg.isVisible = loadState is LoadState.Error } }
Java
class LoadStateViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; private TextView mErrorMsg; private Button mRetry; LoadStateViewHolder( @NonNull ViewGroup parent, @NonNull View.OnClickListener retryCallback) { super(LayoutInflater.from(parent.getContext()) .inflate(R.layout.load_state_item, parent, false)); LoadStateItemBinding binding = LoadStateItemBinding.bind(itemView); mProgressBar = binding.progressBar; mErrorMsg = binding.errorMsg; mRetry = binding.retryButton; } public void bind(LoadState loadState) { if (loadState instanceof LoadState.Error) { LoadState.Error loadStateError = (LoadState.Error) loadState; mErrorMsg.setText(loadStateError.getError().getLocalizedMessage()); } mProgressBar.setVisibility(loadState instanceof LoadState.Loading ? View.VISIBLE : View.GONE); mRetry.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); mErrorMsg.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); } }
Java
class LoadStateViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; private TextView mErrorMsg; private Button mRetry; LoadStateViewHolder( @NonNull ViewGroup parent, @NonNull View.OnClickListener retryCallback) { super(LayoutInflater.from(parent.getContext()) .inflate(R.layout.load_state_item, parent, false)); LoadStateItemBinding binding = LoadStateItemBinding.bind(itemView); mProgressBar = binding.progressBar; mErrorMsg = binding.errorMsg; mRetry = binding.retryButton; } public void bind(LoadState loadState) { if (loadState instanceof LoadState.Error) { LoadState.Error loadStateError = (LoadState.Error) loadState; mErrorMsg.setText(loadStateError.getError().getLocalizedMessage()); } mProgressBar.setVisibility(loadState instanceof LoadState.Loading ? View.VISIBLE : View.GONE); mRetry.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); mErrorMsg.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); } }
Erstellen Sie als Nächstes eine Klasse, die LoadStateAdapter
implementiert, und definieren Sie die
onCreateViewHolder()
und
onBindViewHolder()
. Mit diesen Methoden wird eine Instanz des Halters der benutzerdefinierten Ansicht erstellt und gebunden.
zugehöriger Ladestatus.
Kotlin
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter( private val retry: () -> Unit ) : LoadStateAdapter<LoadStateViewHolder>() { override fun onCreateViewHolder( parent: ViewGroup, loadState: LoadState ) = LoadStateViewHolder(parent, retry) override fun onBindViewHolder( holder: LoadStateViewHolder, loadState: LoadState ) = holder.bind(loadState) }
Java
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter extends LoadStateAdapter<LoadStateViewHolder> { private View.OnClickListener mRetryCallback; ExampleLoadStateAdapter(View.OnClickListener retryCallback) { mRetryCallback = retryCallback; } @NotNull @Override public LoadStateViewHolder onCreateViewHolder(@NotNull ViewGroup parent, @NotNull LoadState loadState) { return new LoadStateViewHolder(parent, mRetryCallback); } @Override public void onBindViewHolder(@NotNull LoadStateViewHolder holder, @NotNull LoadState loadState) { holder.bind(loadState); } }
Java
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter extends LoadStateAdapter<LoadStateViewHolder> { private View.OnClickListener mRetryCallback; ExampleLoadStateAdapter(View.OnClickListener retryCallback) { mRetryCallback = retryCallback; } @NotNull @Override public LoadStateViewHolder onCreateViewHolder(@NotNull ViewGroup parent, @NotNull LoadState loadState) { return new LoadStateViewHolder(parent, mRetryCallback); } @Override public void onBindViewHolder(@NotNull LoadStateViewHolder holder, @NotNull LoadState loadState) { holder.bind(loadState); } }
Ladestatus als Kopf- oder Fußzeile anzeigen
Um den Ladefortschritt in einer Kopf- und Fußzeile anzuzeigen, rufen Sie die Methode
withLoadStateHeaderAndFooter()
aus dem PagingDataAdapter
-Objekt:
Kotlin
pagingAdapter .withLoadStateHeaderAndFooter( header = ExampleLoadStateAdapter(adapter::retry), footer = ExampleLoadStateAdapter(adapter::retry) )
Java
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
Java
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
Sie können stattdessen folgende Nummer anrufen:
withLoadStateHeader()
oder
withLoadStateFooter()
wenn Sie möchten, dass die RecyclerView
-Liste den Ladestatus nur im
oder nur in der Fußzeile.
Auf zusätzliche Informationen zum Ladestatus zugreifen
Das CombinedLoadStates
-Objekt von PagingDataAdapter
liefert Informationen zu
die Ladestatus für Ihre PagingSource
-Implementierung und auch für Ihre
RemoteMediator
-Implementierung, falls vorhanden.
Der Einfachheit halber können Sie
refresh
,
append
und
prepend
Eigenschaften von CombinedLoadStates
auf ein LoadState
-Objekt für die
passenden Ladetyp aus. Diese Properties rufen in der Regel den Ladestatus vom
die RemoteMediator
-Implementierung, falls vorhanden; Andernfalls enthalten sie den Parameter
entsprechenden Ladestatus aus der PagingSource
-Implementierung. Detailliertere Informationen
Informationen zur zugrunde liegenden Logik finden Sie in der Referenzdokumentation zu
CombinedLoadStates
Kotlin
lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. refreshLoadState: LoadState = loadStates.refresh // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. prependLoadState: LoadState = loadStates.prepend // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. appendLoadState: LoadState = loadStates.append } }
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState refreshLoadState = loadStates.refresh; // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState prependLoadState = loadStates.prepend; // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState appendLoadState = loadStates.append; });
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState refreshLoadState = loadStates.refresh; // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState prependLoadState = loadStates.prepend; // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState appendLoadState = loadStates.append; });
Beachten Sie jedoch, dass nur die Ladestatus PagingSource
synchron mit UI-Updates. Da die refresh
,
Die Properties append
und prepend
können möglicherweise den Ladestatus von
entweder PagingSource
oder RemoteMediator
, werden diese
synchron mit UI-Updates. Dies kann zu Problemen mit der Benutzeroberfläche führen.
bis die neuen Daten der Benutzeroberfläche hinzugefügt wurden.
Aus diesem Grund eignen sich die Convenience-Zugriffsfunktionen gut für die Anzeige der Last
in einer Kopf- oder Fußzeile sein. Für andere Anwendungsfälle müssen Sie
auf den Ladestatus entweder über PagingSource
oder
RemoteMediator
. CombinedLoadStates
stellt die
source
und
mediator
für diesen Zweck verwenden. Diese Eigenschaften stellen jeweils ein
LoadStates
-Objekt, das
enthält die LoadState
-Objekte für PagingSource
oder RemoteMediator
Entsprechend:
Kotlin
lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> // Directly access the RemoteMediator refresh load state. mediatorRefreshLoadState: LoadState? = loadStates.mediator.refresh // Directly access the RemoteMediator append load state. mediatorAppendLoadState: LoadState? = loadStates.mediator.append // Directly access the RemoteMediator prepend load state. mediatorPrependLoadState: LoadState? = loadStates.mediator.prepend // Directly access the PagingSource refresh load state. sourceRefreshLoadState: LoadState = loadStates.source.refresh // Directly access the PagingSource append load state. sourceAppendLoadState: LoadState = loadStates.source.append // Directly access the PagingSource prepend load state. sourcePrependLoadState: LoadState = loadStates.source.prepend } }
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Directly access the RemoteMediator refresh load state. LoadState mediatorRefreshLoadState = loadStates.mediator.refresh; // Directly access the RemoteMediator append load state. LoadState mediatorAppendLoadState = loadStates.mediator.append; // Directly access the RemoteMediator prepend load state. LoadState mediatorPrependLoadState = loadStates.mediator.prepend; // Directly access the PagingSource refresh load state. LoadState sourceRefreshLoadState = loadStates.source.refresh; // Directly access the PagingSource append load state. LoadState sourceAppendLoadState = loadStates.source.append; // Directly access the PagingSource prepend load state. LoadState sourcePrependLoadState = loadStates.source.prepend; });
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Directly access the RemoteMediator refresh load state. LoadState mediatorRefreshLoadState = loadStates.mediator.refresh; // Directly access the RemoteMediator append load state. LoadState mediatorAppendLoadState = loadStates.mediator.append; // Directly access the RemoteMediator prepend load state. LoadState mediatorPrependLoadState = loadStates.mediator.prepend; // Directly access the PagingSource refresh load state. LoadState sourceRefreshLoadState = loadStates.source.refresh; // Directly access the PagingSource append load state. LoadState sourceAppendLoadState = loadStates.source.append; // Directly access the PagingSource prepend load state. LoadState sourcePrependLoadState = loadStates.source.prepend; });
Kettenoperatoren bei LoadState
Da das CombinedLoadStates
-Objekt Zugriff auf alle Änderungen in
ist es wichtig, den Laststatusstream auf der Grundlage bestimmter
Ereignisse. Dadurch wird sichergestellt, dass Sie Ihre UI zum richtigen Zeitpunkt aktualisieren, um
und unnötige Aktualisierungen der Benutzeroberfläche.
Angenommen, Sie möchten eine leere Ansicht anzeigen, aber erst nach dem
das anfängliche Laden der Daten abgeschlossen ist. Für diesen Anwendungsfall müssen Sie überprüfen,
Aktualisierungsladevorgang gestartet wurde. Warten Sie dann, bis der Status NotLoading
bestätigt, dass
die Aktualisierung abgeschlossen ist. Sie müssen alle Signale bis auf die herausfiltern.
Sie benötigen:
Kotlin
lifecycleScope.launchWhenCreated { adapter.loadStateFlow // Only emit when REFRESH LoadState for RemoteMediator changes. .distinctUntilChangedBy { it.refresh } // Only react to cases where REFRESH completes, such as NotLoading. .filter { it.refresh is LoadState.NotLoading } // Scroll to top is synchronous with UI updates, even if remote load was // triggered. .collect { binding.list.scrollToPosition(0) } }
Java
PublishSubject<CombinedLoadStates> subject = PublishSubject.create(); Disposable disposable = subject.distinctUntilChanged(CombinedLoadStates::getRefresh) .filter( combinedLoadStates -> combinedLoadStates.getRefresh() instanceof LoadState.NotLoading) .subscribe(combinedLoadStates -> binding.list.scrollToPosition(0)); pagingAdapter.addLoadStateListener(loadStates -> { subject.onNext(loadStates); });
Java
LiveData<CombinedLoadStates> liveData = new MutableLiveData<>(); LiveData<LoadState> refreshLiveData = Transformations.map(liveData, CombinedLoadStates::getRefresh); LiveData<LoadState> distinctLiveData = Transformations.distinctUntilChanged(refreshLiveData); distinctLiveData.observeForever(loadState -> { if (loadState instanceof LoadState.NotLoading) { binding.list.scrollToPosition(0); } });
In diesem Beispiel wird gewartet, bis der Ladestatus der Aktualisierung aktualisiert wurde. Es wird aber nur ausgelöst,
wenn der Status NotLoading
ist. Dadurch wird sichergestellt, dass bei der Remote-Aktualisierung
bevor Änderungen an der Benutzeroberfläche erfolgen.
Stream-APIs machen diese Art von Vorgang möglich. Ihre Anwendung kann die Last angeben, und verarbeiten die neuen Daten, wenn die entsprechenden Kriterien erfüllt sind.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Daten aus Seiten laden und anzeigen
- Seite aus Netzwerk und Datenbank
- Paging Library