La libreria Paging tiene traccia dello stato delle richieste di caricamento per i dati paginati e lo espone tramite la classe LoadState.
Per ogni LoadType e tipo di origine dati (PagingSource o RemoteMediator) viene fornito un segnale LoadState separato. L'oggetto CombinedLoadStates fornito dal listener fornisce informazioni sullo stato di caricamento di tutti questi segnali. Puoi utilizzare queste informazioni dettagliate per mostrare agli utenti gli indicatori di caricamento appropriati.
Caricamento stati in corso…
La libreria Paging espone lo stato di caricamento per l'utilizzo nell'interfaccia utente tramite l'oggetto
LoadState. Gli oggetti LoadState assumono una delle tre forme a seconda dello stato di caricamento corrente:
- Se non è presente alcuna operazione di caricamento attiva e nessun errore,
LoadStateè un oggettoLoadState.NotLoading. Questa sottoclasse include anche la proprietàendOfPaginationReached, che indica se è stata raggiunta la fine della paginazione. - Se è presente un'operazione di caricamento attiva,
LoadStateè un oggettoLoadState.Loading. - Se si verifica un errore,
LoadStateè un oggettoLoadState.Error.
Accedi a questi stati tramite la proprietà loadState del wrapper
LazyPagingItems. Puoi utilizzare questo stato in due modi: gestendo
la visibilità dei contenuti principali (ad esempio un indicatore di aggiornamento a schermo intero) o inserendo
elementi di caricamento direttamente nel tuo stream LazyColumn (ad esempio un indicatore a piè di pagina).
Accedere allo stato di caricamento con un listener
Per monitorare lo stato di caricamento nell'interfaccia utente, utilizza la proprietà loadState
fornita dal wrapper LazyPagingItems. Restituisce un oggetto
CombinedLoadStates che consente di reagire al comportamento di caricamento per
eventi di aggiornamento, aggiunta o anteposizione.
Nell'esempio seguente, la UI mostra una rotellina di caricamento o un messaggio di errore a seconda dello stato attuale del caricamento dell'aggiornamento (iniziale):
@Composable fun UserListScreen(viewModel: UserViewModel) { val pagingItems = viewModel.flow.collectAsLazyPagingItems() Box(modifier = Modifier.fillMaxSize()) { // Show the list content LazyColumn { items(pagingItems.itemCount) { index -> UserItem(pagingItems[index]) } } // Handle the loading state when (val state = pagingItems.loadState.refresh) { is LoadState.Loading -> { CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) } is LoadState.Error -> { ErrorButton( message = state.error.message ?: "Unknown error", onClick = { pagingItems.retry() }, modifier = Modifier.align(Alignment.Center) ) } else -> {} // No separate view needed for success/not loading } } }
Per maggiori informazioni su LazyPagingItems, consulta Set di dati di grandi dimensioni (impaginazione).
Aggiungere intestazioni e piè di pagina di caricamento
Per visualizzare gli indicatori di caricamento all'inizio o alla fine dell'elenco (che fungono da
intestazioni o piè di pagina), aggiungi blocchi di elementi dedicati specificamente a questi stati
all'interno dell'ambito LazyColumn.
Puoi monitorare lo stato di pre-inserimento per l'intestazione e lo stato di accodamento per il
piè di pagina utilizzando l'oggetto CombinedLoadStates.
Nell'esempio seguente, l'elenco mostra una barra di avanzamento o un pulsante Riprova nella parte inferiore dell'elenco quando vengono recuperati altri dati:
@Composable fun UserList(viewModel: UserViewModel) { val pagingItems = viewModel.pager.flow.collectAsLazyPagingItems() LazyColumn { // 1. Header (Prepend state) // Useful if you support bidirectional paging or jumping to the middle item { val prependState = pagingItems.loadState.prepend if (prependState is LoadState.Loading) { LoadingItem() } else if (prependState is LoadState.Error) { ErrorItem( message = prependState.error.message ?: "Error", onClick = { pagingItems.retry() } ) } } // 2. Main Data items(pagingItems.itemCount) { index -> UserItem(pagingItems[index]) } // 3. Footer (Append state) // Shows when the user scrolls to the bottom and more data is loading item { val appendState = pagingItems.loadState.append if (appendState is LoadState.Loading) { LoadingItem() } else if (appendState is LoadState.Error) { ErrorItem( message = appendState.error.message ?: "Error", onClick = { pagingItems.retry() } ) } } } } @Composable fun LoadingItem() { Box(modifier = Modifier.fillMaxWidth().padding(16.dp), contentAlignment = Alignment.Center) { CircularProgressIndicator() } } @Composable fun ErrorItem(message: String, onClick: () -> Unit) { Column( modifier = Modifier.fillMaxWidth().padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = message, color = Color.Red) Button(onClick = onClick) { Text("Retry") } } }
Accedere a informazioni aggiuntive sullo stato di caricamento
Come mostrato negli esempi precedenti, chiamare pagingItems.loadState.refresh è
comodo. Tuttavia, offusca la differenza tra il caricamento dal database locale (PagingSource) e dalla rete (RemoteMediator).
Ciò può causare la visualizzazione temporanea di un indicatore di caricamento nell'interfaccia utente anche quando i dati memorizzati nella cache sono immediatamente disponibili.
Per un controllo preciso, ad esempio per mostrare un indicatore di caricamento solo quando il database locale
è vuoto e la sincronizzazione di rete è attiva, accedi alle proprietà source e mediator
direttamente all'interno del composable.
val loadState = pagingItems.loadState val isSyncing = loadState.mediator?.refresh is LoadState.Loading val isLocalEmpty = loadState.source.refresh is LoadState.NotLoading && pagingItems.itemSnapshotList.items.isEmpty() if (isSyncing && isLocalEmpty) { FullScreenLoading() } else { UserList(pagingItems) if (isSyncing) { TopOverlaySpinner() } }
Reagire alle modifiche dello stato di caricamento
Potresti dover attivare effetti collaterali una tantum in base alle modifiche dello stato di caricamento,
ad esempio scorrere fino all'inizio di un elenco o mostrare un Snackbar al termine
di un aggiornamento.
Utilizza snapshotFlow all'interno di un LaunchedEffect per osservare le modifiche dello stato come
stream. In questo modo puoi applicare operatori Flow standard come filter
e distinctUntilChanged per isolare eventi specifici.
val listState = rememberLazyListState() LaunchedEffect(pagingItems) { // 1. Convert the state to a Flow snapshotFlow { pagingItems.loadState.refresh } // 2. Filter for the specific event (Refresh completed successfully) .distinctUntilChanged() .filter { it is LoadState.NotLoading } .collect { // 3. Trigger the side effect listState.animateScrollToItem(0) } }
Risorse aggiuntive
Per ulteriori informazioni sulla libreria Paging e sugli stati di caricamento, consulta le seguenti risorse.
Documentazione
Visualizza contenuti
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Panoramica della libreria Paging