Yükleme durumlarını yönetme ve sunma

Paging kitaplığı, sayfalandırılmış veriler için yükleme isteklerinin durumunu izler ve LoadState sınıfı aracılığıyla kullanıma sunar.

Her LoadState ve veri kaynağı türü (LoadType veya PagingSource) için ayrı bir RemoteMediator sinyali sağlanır. Dinleyici tarafından sağlanan CombinedLoadStates nesnesi, bu sinyallerin tümünden 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ığı, LoadState nesnesi aracılığıyla kullanıcı arayüzünde kullanılmak üzere yükleme durumunu gösterir. LoadState nesneleri, mevcut yükleme durumuna bağlı olarak üç biçimden birini alır:

Bu durumlara LazyPagingItems sarmalayıcınızın loadState özelliği üzerinden erişin. Bu durumu iki şekilde kullanabilirsiniz: Ana içerik görünürlüğünü (ör. tam ekran yenileme yükleme animasyonu) işleme veya yükleme öğelerini doğrudan LazyColumn akışınıza (ör. altbilgi yükleme animasyonu) ekleme.

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 ön ekleme etkinliklerinin yükleme davranışına tepki vermenizi sağlayan bir CombinedLoadStates nesnesi döndürür.

Aşağıdaki örnekte, yenileme (ilk) yüklemenin mevcut durumuna bağlı olarak kullanıcı arayüzünde yükleme döner simgesi veya hata mesajı gösterilir:

@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.

Listenizin başında veya sonunda yükleme göstergeleri (başlık veya altbilgi olarak) göstermek için LazyColumn kapsamınızda bu durumlar için özel öğe blokları ekleyin.

CombinedLoadStates nesnesini kullanarak başlık için önek durumunu, altbilgi için ise sonek durumunu izleyebilirsiniz.

Aşağıdaki örnekte, daha fazla veri getirilirken listenin en altı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") }
  }
}

Ek yükleme durumu bilgilerine erişme

Daha önceki örneklerde gösterildiği gibi, arama yapmak pagingItems.loadState.refresh kolaydır. Ancak bu, yerel veritabanınızdan (PagingSource) ve ağınızdan (RemoteMediator) yükleme arasındaki farkı gizler. Bu durum, önbelleğe alınmış veriler anında kullanılabilir olsa bile kullanıcı arayüzünün kısa süreliğine yükleme animasyonu göstermesine neden olabilir.

Yerel veritabanı boş olduğunda ve ağ senkronizasyonu etkin olduğunda yükleme animasyonunu gösterme 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()
    }
}

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 liste yenilendiğinde listenin en üstüne kaydırma veya yenileme işlemi tamamlandığında Snackbar gösterme gibi.

Durum değişikliklerini akış olarak gözlemlemek için snapshotFlow öğesini LaunchedEffect içinde kullanın. Bu sayede, belirli etkinlikleri diğerlerinden ayırmak için filter ve distinctUntilChanged 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)
    }
}

Ek kaynaklar

Paging kitaplığı ve yükleme durumları hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.

Belgeler

İçeriği görüntüleme