Paging kitaplığı, sayfalı veriler için yükleme isteklerinin durumunu takip eder ve bu durumu LoadState sınıfı üzerinden gösterir.
Her LoadType ve veri kaynağı türü (PagingSource veya RemoteMediator) için ayrı bir LoadState sinyali sağlanır. İşleyici tarafından sağlanan CombinedLoadStates nesnesi, tüm bu sinyallerden yükleme durumu hakkında bilgi sağlar. Bu ayrıntılı bilgileri kullanarak kullanıcılarınıza uygun yükleme göstergelerini gösterebilirsiniz.
Yükleme durumları
Paging kitaplığı, kullanıcı arayüzünde kullanılacak yükleme durumunu LoadState nesnesi aracılığıyla gösterir. LoadState nesneleri, mevcut yükleme durumuna bağlı olarak üç biçimden birini alır:
- Etkin bir yükleme işlemi ve hata yoksa
LoadState, birLoadState.NotLoadingnesnesidir. Bu alt sınıf, sayfalama işleminin sonuna ulaşıp ulaşılmadığını gösterenendOfPaginationReachedözelliğini de içerir. - Etkin bir yükleme işlemi varsa
LoadStatebirLoadState.Loadingnesnesidir. - Hata varsa
LoadStatebirLoadState.Errornesnesidir.
Bu durumlara LazyPagingItems sarmalayıcınızın loadState özelliği aracılığıyla erişin. Bu durumu iki şekilde kullanabilirsiniz: Ana içeriğin görünürlüğünü yönetme (tam ekran yenileme döndürücüsü gibi) veya yükleme öğelerini doğrudan LazyColumn akışınıza ekleme (altbilgi döndürücüsü gibi).
Yükleme durumuna bir dinleyiciyle erişme
Kullanıcı arayüzünüzdeki yükleme durumunu izlemek için LazyPagingItems sarmalayıcısı tarafından sağlanan loadState özelliğini kullanın. Bu, yenileme, ekleme veya başa ekleme etkinlikleri için yükleme davranışına tepki vermenizi sağlayan bir CombinedLoadStates nesnesi döndürür.
Aşağıdaki örnekte kullanıcı arayüzü, yenileme (ilk) yüklemesinin mevcut durumuna bağlı olarak bir yükleme döner simgesi veya hata mesajı gösterir:
@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 } } }
LazyPagingItems hakkında daha fazla bilgi için Büyük veri kümeleri (sayfalama) başlıklı makaleyi inceleyin.
Yükleme üstbilgileri ve altbilgileri ekleme
Listenizin başında veya sonunda yükleme göstergeleri görüntülemek (üstbilgi veya altbilgi olarak) için LazyColumn kapsamınızda özellikle bu durumlar için özel öğe blokları ekleyin.
CombinedLoadStates nesnesini kullanarak üstbilginin başa ekleme durumunu ve altbilginin sona ekleme durumunu izleyebilirsiniz.
Aşağıdaki örnekte, daha fazla veri getirilirken listenin alt kısmında bir ilerleme çubuğu veya yeniden deneme düğmesi gösterilmektedir:
@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") } } }
Yükleme durumuyla ilgili ek bilgilere erişme
Önceki örneklerde gösterildiği gibi pagingItems.loadState.refresh'i aramak kolaydır. Ancak yerel veritabanınızdan (PagingSource) ve ağınızdan (RemoteMediator) yükleme arasındaki farkı gizler. Bu durum, önbelleğe alınmış veriler hemen kullanılabilir olsa bile kullanıcı arayüzünün kısa bir süre için yükleme animasyonu göstermesine neden olabilir.
Yerel veritabanı boşken ve ağ senkronizasyonu etkinken yükleme animasyonu göstermek gibi hassas kontrol için source ve mediator özelliklerine doğrudan composable'ınızdan erişin.
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() } }
pagingItems.loadState, kaydırma sırasında prepend veya append her değiştiğinde yeni bir CombinedLoadStates nesnesi yayınladığından yenileme kontrolünü remember(pagingItems) ile derivedStateOf içine sarmalayın. Bu sayede, kaydırma kenarı güncellemelerinin yalnızca tam ekran yenileme göstergesini açıp kapatan bir üst kapsamı yeniden oluşturması önlenir:
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() } }
Yükleme durumu değişikliklerine tepki verme
Yükleme durumu değişikliklerine göre tek seferlik yan etkileri tetiklemeniz gerekebilir. Örneğin, bir listenin en üstüne kaydırma veya yenileme tamamlandığında ya da başarısız olduğunda Snackbar gösterme gibi.
Durum değişikliklerini akış olarak gözlemlemek için LaunchedEffect içinde snapshotFlow kullanın. Bu sayede, belirli etkinlikleri ayırmak için filter, distinctUntilChanged ve distinctUntilChangedBy gibi standart Flow operatörlerini uygulayabilirsiniz.
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) } }
Benzer şekilde, yalnızca refresh durumu LoadState.Error değerine geçtiğinde bir hata Snackbar göstermek için loadState üzerinde distinctUntilChangedBy kullanabilirsiniz:
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() } } }
Ek kaynaklar
Paging kitaplığı ve yükleme durumları hakkında daha fazla bilgi için aşağıdaki kaynakları inceleyin.
Belgeler
İçerik görüntüleme
Sizin için önerilenler
- Not: JavaScript devre dışı olduğunda bağlantı metni gösterilir.
- Paging kitaplığına genel bakış