Libary Paging melacak status permintaan pemuatan untuk data yang di-page dan menampilkannya
melalui class LoadState.
Sinyal LoadState terpisah diberikan untuk setiapLoadType dan jenis sumber data
(PagingSource atau
RemoteMediator). Objek
CombinedLoadStates
yang diberikan oleh pemroses berisi informasi tentang status pemuatan
dari semua sinyal ini. Anda dapat menggunakan informasi mendetail ini untuk menampilkan
indikator pemuatan yang sesuai untuk pengguna Anda.
Status pemuatan
Library Paging menampilkan status pemuatan untuk digunakan di UI melalui
objek LoadState. Objek LoadState mengambil salah satu dari tiga bentuk, bergantung pada
status pemuatan saat ini:
- Jika tidak ada operasi pemuatan yang aktif dan tidak ada error,
LoadStateadalah objekLoadState.NotLoading. Subclass ini juga menyertakan propertiendOfPaginationReached, yang menunjukkan apakah akhir penomoran halaman telah tercapai. - Jika ada operasi pemuatan yang aktif,
LoadStateadalah objekLoadState.Loading. - Jika ada error,
LoadStateadalah objekLoadState.Error.
Akses status ini melalui properti loadState wrapper
LazyPagingItems Anda. Anda dapat menggunakan status ini dengan dua cara: menangani
visibilitas konten utama (seperti indikator lingkaran berputar refresh layar penuh) atau menyisipkan
item pemuatan langsung ke aliran data LazyColumn (seperti indikator lingkaran berputar footer).
Mengakses status pemuatan dengan pemroses
Untuk memantau status pemuatan di UI, gunakan properti loadState
yang disediakan oleh wrapper LazyPagingItems. Tindakan ini akan menampilkan objek
CombinedLoadStates yang memungkinkan Anda bereaksi terhadap perilaku pemuatan untuk
peristiwa refresh, penambahan, atau penambahan di awal.
Dalam contoh berikut, UI menampilkan indikator lingkaran berputar untuk pemuatan atau pesan error, bergantung pada status pemuatan refresh (awal) saat ini:
@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 } } }
Untuk mengetahui informasi selengkapnya tentang LazyPagingItems, lihat Set data besar (paging).
Menambahkan header dan footer pemuatan
Untuk menampilkan indikator pemuatan di awal atau akhir daftar (berfungsi sebagai
header atau footer), tambahkan blok item khusus untuk status tersebut
dalam cakupan LazyColumn Anda.
Anda dapat memantau status penambahan di awal untuk header dan status penambahan di akhir untuk
footer menggunakan objek CombinedLoadStates.
Dalam contoh berikut, daftar menampilkan status progres atau tombol coba lagi di bagian bawah daftar saat lebih banyak data diambil:
@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") } } }
Mengakses informasi status pemuatan tambahan
Seperti yang ditunjukkan dalam contoh sebelumnya, memanggil pagingItems.loadState.refresh sangatlah mudah. Namun, hal ini mengaburkan perbedaan antara pemuatan dari database lokal (PagingSource) dan jaringan (RemoteMediator). Hal ini dapat menyebabkan UI menampilkan indikator lingkaran berputar pemuatan secara singkat meskipun data yang di-cache langsung tersedia.
Untuk kontrol yang akurat, seperti menampilkan indikator lingkaran berputar hanya saat database lokal
kosong dan sinkronisasi jaringan aktif, akses properti source dan mediator
langsung dalam composable Anda.
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() } }
Karena pagingItems.loadState memunculkan objek CombinedLoadStates baru setiap kali
prepend atau append berubah selama men-scroll, gabungkan pemeriksaan refresh di
derivedStateOf dengan remember(pagingItems). Hal ini mencegah update scroll-edge
merekomposisi cakupan induk yang hanya mengalihkan indikator refresh
layar penuh:
val showFullScreenLoading by remember(pagingItems) { derivedStateOf { // Avoid recomposing on prepend or append updates while scrolling, and // avoid covering existing items during a background refresh. pagingItems.loadState.source.refresh is LoadState.Loading && pagingItems.itemCount == 0 } } if (showFullScreenLoading) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { CircularProgressIndicator() } }
Merespons perubahan status pemuatan
Anda mungkin perlu memicu efek samping satu kali berdasarkan perubahan status pemuatan,
seperti men-scroll ke bagian atas daftar atau menampilkan Snackbar saat pemuatan ulang
selesai atau gagal.
Gunakan snapshotFlow di dalam LaunchedEffect untuk mengamati perubahan status sebagai
aliran data. Dengan begitu, Anda dapat menerapkan operator Flow standar seperti filter,
distinctUntilChanged, dan distinctUntilChangedBy untuk mengisolasi
peristiwa tertentu.
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) } }
Demikian pula, Anda dapat menggunakan distinctUntilChangedBy di loadState untuk menampilkan
Snackbar error hanya saat status refresh bertransisi ke
LoadState.Error:
val snackbarHostState = remember { SnackbarHostState() } // Key on pagingItems rather than loadState so state updates do not restart the // coroutine and reset distinctUntilChangedBy. LaunchedEffect(pagingItems) { snapshotFlow { pagingItems.loadState } // Ignore prepend and append updates so scrolling does not re-trigger the // refresh error Snackbar. .distinctUntilChangedBy { it.refresh } .filter { it.refresh is LoadState.Error } .collect { loadState -> val error = (loadState.refresh as LoadState.Error).error val result = snackbarHostState.showSnackbar( message = "Data failed to load: ${error.localizedMessage ?: "Unknown error"}", actionLabel = "Retry" ) if (result == SnackbarResult.ActionPerformed) { pagingItems.retry() } } }
Referensi lainnya
Untuk informasi selengkapnya tentang library Paging dan status pemuatan, lihat referensi berikut.
Dokumentasi
Konten penayangan
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Ringkasan library paging