Thư viện phân trang theo dõi trạng thái của các yêu cầu tải dữ liệu được phân trang và hiển thị
thông qua lớp LoadState.
Bạn có thể cung cấp tín hiệu LoadState riêng biệt cho từng
LoadType và loại nguồn dữ liệu
(PagingSource hoặc
RemoteMediator). Đối tượng
CombinedLoadStates
do trình nghe cung cấp cung cấp thông tin về trạng thái tải
của tất cả tín hiệu này. Bạn có thể dùng thông tin chi tiết này để hiện các chỉ báo tải phù hợp cho người dùng.
Các trạng thái đang tải
Thư viện phân trang hiện trạng thái tải để sử dụng trong UI (giao diện người dùng) thông qua đối tượng LoadState. Các đối tượng LoadState có một trong ba dạng tuỳ thuộc vào trạng thái tải hiện tại:
- Nếu không có hoạt động tải nào đang hoạt động và không có lỗi, thì
LoadStatelà đối tượngLoadState.NotLoading. Lớp con này cũng bao gồm thuộc tínhendOfPaginationReached, cho biết liệu đã đến cuối quá trình phân trang hay chưa. - Nếu có một hoạt động tải đang hoạt động, thì
LoadStatelà đối tượngLoadState.Loading. - Nếu xảy ra lỗi thì
LoadStatelà đối tượngLoadState.Error.
Truy cập vào các trạng thái này thông qua thuộc tính loadState của trình bao bọc
LazyPagingItems. Bạn có thể sử dụng trạng thái này theo hai cách: xử lý khả năng hiển thị nội dung chính (như vòng quay làm mới toàn màn hình) hoặc chèn các mục tải trực tiếp vào luồng LazyColumn (như vòng quay chân trang).
Truy cập trạng thái đang tải bằng một trình nghe
Để theo dõi trạng thái đang tải trong giao diện người dùng, hãy sử dụng thuộc tính loadState
do trình bao bọc LazyPagingItems cung cấp. Thuộc tính này trả về một
CombinedLoadStates đối tượng cho phép bạn phản ứng với hành vi tải đối với
các sự kiện làm mới, thêm hoặc thêm vào đầu.
Trong ví dụ sau, giao diện người dùng hiển thị một vòng quay tải hoặc một thông báo lỗi tuỳ thuộc vào trạng thái hiện tại của quá trình tải làm mới (ban đầu):
@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 } } }
Để biết thêm thông tin về LazyPagingItems, hãy xem Các tập dữ liệu lớn (phân trang).
Thêm đầu trang và chân trang tải
Để hiển thị các chỉ báo tải ở đầu hoặc cuối danh sách (đóng vai trò là đầu trang hoặc chân trang), hãy thêm các khối mục dành riêng cho các trạng thái đó trong phạm vi LazyColumn.
Bạn có thể theo dõi trạng thái thêm vào đầu cho đầu trang và trạng thái thêm vào cuối cho
chân trang bằng CombinedLoadStates đối tượng.
Trong ví dụ sau, danh sách hiển thị một thanh tiến trình hoặc một nút thử lại ở cuối danh sách khi đang tìm nạp thêm dữ liệu:
@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") } } }
Truy cập các thông tin bổ sung về trạng thái đang tải
Như trong các ví dụ trước, việc gọi pagingItems.loadState.refresh rất tiện lợi. Tuy nhiên, thao tác này sẽ che khuất sự khác biệt giữa việc tải từ cơ sở dữ liệu cục bộ (PagingSource) và
mạng (RemoteMediator).
Điều này có thể khiến giao diện người dùng hiển thị nhanh một vòng quay tải ngay cả khi dữ liệu được lưu vào bộ nhớ đệm
có sẵn ngay lập tức.
Để kiểm soát chính xác, chẳng hạn như chỉ hiển thị vòng quay tải khi cơ sở dữ liệu cục bộ trống và quá trình đồng bộ hoá mạng đang hoạt động, hãy truy cập trực tiếp vào các thuộc tính source và mediator trong thành phần kết hợp.
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() } }
Phản ứng với các thay đổi về trạng thái tải
Bạn có thể cần kích hoạt các hiệu ứng phụ một lần dựa trên các thay đổi về trạng thái tải, chẳng hạn như cuộn lên đầu danh sách hoặc hiển thị Snackbar khi quá trình làm mới hoàn tất.
Sử dụng snapshotFlow bên trong LaunchedEffect để quan sát các thay đổi về trạng thái dưới dạng luồng. Điều này cho phép bạn áp dụng các toán tử tiêu chuẩn Flow như filter
và distinctUntilChanged để tách biệt các sự kiện cụ thể.
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) } }
Tài nguyên khác
Để biết thêm thông tin về thư viện Phân trang và trạng thái tải, hãy tham khảo các tài nguyên sau.
Tài liệu
Nội dung khung hiển thị
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Tổng quan về thư viện Paging