Biblioteka Paging śledzi stan żądań wczytywania danych podzielonych na strony i udostępnia go za pomocą klasy LoadState.
Dla każdego LoadState sygnału udostępniany jest oddzielny sygnał LoadType i typ źródła danych (PagingSource lub RemoteMediator). Obiekt CombinedLoadStates udostępniany przez odbiornik zawiera informacje o stanie wczytywania ze wszystkich tych sygnałów. Możesz użyć tych szczegółowych informacji, aby wyświetlać użytkownikom odpowiednie wskaźniki wczytywania.
Wczytuję stany
Biblioteka Paging udostępnia stan wczytywania do użycia w interfejsie za pomocą obiektu LoadState. LoadState obiekty przyjmują jedną z 3 form w zależności od bieżącego stanu wczytywania:
- Jeśli nie ma aktywnej operacji wczytywania i nie wystąpił żaden błąd,
LoadStatejest obiektemLoadState.NotLoading. Ta podklasa zawiera też właściwośćendOfPaginationReached, która wskazuje, czy osiągnięto koniec paginacji. - Jeśli trwa aktywna operacja wczytywania,
LoadStatejest obiektemLoadState.Loading. - Jeśli wystąpi błąd,
LoadStatejest obiektemLoadState.Error.
Dostęp do tych stanów uzyskasz za pomocą właściwości loadState elementu opakowującego LazyPagingItems. Ten stan możesz wykorzystać na 2 sposoby: do obsługi widoczności głównej treści (np. pełnoekranowego wskaźnika odświeżania) lub do wstawiania elementów wczytywania bezpośrednio do strumienia LazyColumn (np. wskaźnika w stopce).
Dostęp do stanu wczytywania za pomocą detektora
Aby monitorować stan wczytywania w interfejsie, użyj właściwości loadState udostępnianej przez komponent LazyPagingItems. Zwraca obiekt CombinedLoadStates, który umożliwia reagowanie na zachowanie podczas wczytywania w przypadku zdarzeń odświeżania, dołączania lub dodawania na początku.
W poniższym przykładzie interfejs wyświetla wskaźnik postępu wczytywania lub komunikat o błędzie w zależności od bieżącego stanu odświeżania (początkowego wczytywania):
@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 } } }
Więcej informacji o funkcji LazyPagingItems znajdziesz w artykule Duże zbiory danych (stronicowanie).
Dodawanie nagłówków i stopek wczytywania
Aby wyświetlać wskaźniki ładowania na początku lub na końcu listy (jako nagłówki lub stopki), dodaj bloki elementów przeznaczone specjalnie dla tych stanów w zakresie LazyColumn.
Stan dodawania na początku nagłówka i na końcu stopki możesz monitorować za pomocą obiektu CombinedLoadStates.
W tym przykładzie lista wyświetla pasek postępu lub przycisk ponowienia u dołu, gdy pobierane są kolejne dane:
@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") } } }
Dostęp do dodatkowych informacji o stanie wczytywania
Jak pokazują wcześniejsze przykłady, dzwonienie pod numer pagingItems.loadState.refresh jest wygodne. Zaciera to jednak różnicę między wczytywaniem z lokalnej bazy danych (PagingSource) a wczytywaniem z sieci (RemoteMediator). Może to spowodować, że interfejs użytkownika będzie przez chwilę wyświetlać spinner ładowania, nawet jeśli dane z pamięci podręcznej są od razu dostępne.
Aby uzyskać precyzyjną kontrolę, np. wyświetlać wskaźnik ładowania tylko wtedy, gdy lokalna baza danych jest pusta i aktywna jest synchronizacja z siecią, uzyskaj dostęp do właściwości source i mediator bezpośrednio w funkcji kompozycyjnej.
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() } }
Reagowanie na zmiany stanu wczytywania
Możesz potrzebować jednorazowych efektów ubocznych wywoływanych przez zmiany stanu wczytywania, np. przewijania listy do góry lub wyświetlania Snackbar po zakończeniu odświeżania.
Użyj snapshotFlow w LaunchedEffect, aby obserwować zmiany stanu jako strumień. Umożliwia to stosowanie standardowych operatorów Flow, takich jak filter i distinctUntilChanged, do wyodrębniania konkretnych zdarzeń.
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) } }
Dodatkowe materiały
Więcej informacji o bibliotece Paging i stanach wczytywania znajdziesz w tych materiałach.
Dokumentacja
Wyświetlanie treści
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Omówienie biblioteki Paging