La bibliothèque Paging suit l'état des requêtes de chargement pour les données paginées et les expose via la classe LoadState.
Un signal LoadState distinct est fourni pour chaque LoadType et type de source de données (soit PagingSource, soit RemoteMediator). L'objet CombinedLoadStates fourni par l'écouteur apporte des informations sur l'état de chargement de tous ces signaux. Vous pouvez utiliser ces informations détaillées pour afficher les indicateurs de chargement appropriés pour vos utilisateurs.
États de chargement
La bibliothèque Paging expose l'état de chargement en vue de son utilisation dans l'interface utilisateur via l'objet LoadState. Les objets LoadState peuvent prendre l'une des trois formes suivantes selon l'état de chargement actuel :
- S'il n'y a pas d'opération de chargement active ni d'erreur,
LoadStateest un objetLoadState.NotLoading. Cette sous-classe inclut également la propriétéendOfPaginationReached, qui indique si la fin de la pagination a été atteinte. - Si une opération de chargement est active,
LoadStateest un objetLoadState.Loading. - En cas d'erreur,
LoadStateest un objetLoadState.Error.
Accédez à ces états via la propriété loadState de votre wrapper LazyPagingItems. Vous pouvez utiliser cet état de deux manières : en gérant la visibilité du contenu principal (comme un indicateur de chargement en plein écran) ou en insérant des éléments de chargement directement dans votre flux LazyColumn (comme un indicateur de chargement de pied de page).
Accéder à l'état de chargement avec un écouteur
Pour surveiller l'état de chargement dans votre UI, utilisez la propriété loadState fournie par le wrapper LazyPagingItems. Cela renvoie un objet CombinedLoadStates qui vous permet de réagir au comportement de chargement pour les événements d'actualisation, d'ajout ou de préfixation.
Dans l'exemple suivant, l'UI affiche une icône de chargement ou un message d'erreur en fonction de l'état actuel du chargement de l'actualisation (initial) :
@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 } } }
Pour en savoir plus sur LazyPagingItems, consultez Ensembles de données volumineux (pagination).
Ajouter des en-têtes et des pieds de page de chargement
Pour afficher des indicateurs de chargement au début ou à la fin de votre liste (en guise d'en-têtes ou de pieds de page), ajoutez des blocs d'éléments dédiés spécifiquement à ces états dans votre portée LazyColumn.
Vous pouvez surveiller l'état de préfixe de l'en-tête et l'état de suffixe du pied de page à l'aide de l'objet CombinedLoadStates.
Dans l'exemple suivant, la liste affiche une barre de progression ou un bouton "Retry" (Réessayer) en bas de la liste lorsque d'autres données sont en cours de récupération :
@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") } } }
Accéder à des informations supplémentaires sur l'état de chargement
Comme indiqué dans les exemples précédents, l'appel de pagingItems.loadState.refresh est pratique. Toutefois, cela masque la différence entre le chargement à partir de votre base de données locale (PagingSource) et votre réseau (RemoteMediator). Cela peut entraîner l'affichage bref d'une icône de chargement dans l'UI, même lorsque les données mises en cache sont immédiatement disponibles.
Pour un contrôle précis, comme l'affichage d'un indicateur de chargement uniquement lorsque la base de données locale est vide et qu'une synchronisation réseau est active, accédez directement aux propriétés source et mediator dans votre 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() } }
Réagir aux changements d'état de chargement
Vous devrez peut-être déclencher des effets secondaires ponctuels en fonction des changements d'état de chargement, comme faire défiler une liste jusqu'en haut ou afficher un Snackbar lorsqu'une actualisation est terminée.
Utilisez snapshotFlow dans un LaunchedEffect pour observer les changements d'état sous forme de flux. Cela vous permet d'appliquer des opérateurs Flow standards tels que filter et distinctUntilChanged pour isoler des événements spécifiques.
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) } }
Ressources supplémentaires
Pour en savoir plus sur la bibliothèque Paging et les états de chargement, consultez les ressources suivantes.
Documentation
Afficher le contenu
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Présentation de la bibliothèque Paging