مدیریت و ارائه حالت های بارگذاری

کتابخانه Paging وضعیت درخواست‌های بارگذاری برای داده‌های صفحه‌بندی‌شده را ردیابی می‌کند و آن را از طریق کلاس LoadState نمایش می‌دهد.

برای هر نوع LoadType و منبع داده (اعم از PagingSource یا RemoteMediator ) یک سیگنال LoadState جداگانه ارائه می‌شود. شیء CombinedLoadStates که توسط شنونده ارائه می‌شود، اطلاعاتی در مورد وضعیت بارگذاری از همه این سیگنال‌ها ارائه می‌دهد. می‌توانید از این اطلاعات دقیق برای نمایش شاخص‌های بارگذاری مناسب به کاربران خود استفاده کنید.

حالت‌های بارگیری

کتابخانه Paging وضعیت بارگذاری را برای استفاده در رابط کاربری از طریق شیء LoadState نمایش می‌دهد. اشیاء LoadState بسته به وضعیت بارگذاری فعلی، یکی از سه شکل زیر را به خود می‌گیرند:

  • اگر هیچ عملیات بارگذاری فعال و خطایی وجود نداشته باشد، آنگاه LoadState یک شیء LoadState.NotLoading است. این زیرکلاس همچنین شامل ویژگی endOfPaginationReached است که نشان می‌دهد آیا به پایان صفحه‌بندی رسیده‌ایم یا خیر.
  • اگر یک عملیات بارگذاری فعال وجود داشته باشد، آنگاه LoadState یک شیء LoadState.Loading است.
  • اگر خطایی وجود داشته باشد، LoadState یک شیء LoadState.Error است.

از طریق ویژگی loadState مربوط به LazyPagingItems wrapper خود به این وضعیت‌ها دسترسی پیدا کنید. می‌توانید از این وضعیت به دو روش استفاده کنید: مدیریت نمایش محتوای اصلی (مانند یک spinner رفرش تمام صفحه) یا وارد کردن آیتم‌های بارگذاری مستقیماً به جریان LazyColumn خود (مانند یک spinner پاورقی).

دسترسی به وضعیت بارگذاری با یک شنونده

برای نظارت بر وضعیت بارگذاری در رابط کاربری خود، از ویژگی loadState که توسط پوشش LazyPagingItems ارائه شده است، استفاده کنید. این یک شیء CombinedLoadStates را برمی‌گرداند که به شما امکان می‌دهد به رفتار بارگذاری برای رویدادهای refresh، append یا prepend واکنش نشان دهید.

در مثال زیر، رابط کاربری بسته به وضعیت فعلی بارگذاری اولیه (refresh) یک نشانگر بارگذاری یا یک پیام خطا نمایش می‌دهد:

@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 ، به بخش مجموعه داده‌های بزرگ (صفحه‌بندی) مراجعه کنید.

برای نمایش نشانگرهای بارگذاری در ابتدا یا انتهای لیست خود (که به عنوان سرصفحه یا پاصفحه عمل می‌کنند)، بلوک‌های آیتم اختصاصی را به طور خاص برای آن حالت‌ها در محدوده LazyColumn خود اضافه کنید.

شما می‌توانید با استفاده از شیء CombinedLoadStates وضعیت prepend برای هدر و وضعیت append برای فوتر را رصد کنید.

در مثال زیر، وقتی داده‌های بیشتری در حال واکشی هستند، لیست یک نوار پیشرفت یا یک دکمه‌ی تلاش مجدد در پایین لیست نمایش می‌دهد:

@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") }
  }
}

دسترسی به اطلاعات وضعیت بارگذاری اضافی

همانطور که در مثال‌های قبلی نشان داده شد، فراخوانی pagingItems.loadState.refresh راحت است. با این حال، تفاوت بین بارگذاری از پایگاه داده محلی ( PagingSource ) و شبکه شما ( RemoteMediator ) را مبهم می‌کند. این می‌تواند باعث شود که رابط کاربری به طور خلاصه یک spinner بارگذاری را نشان دهد، حتی زمانی که داده‌های ذخیره شده بلافاصله در دسترس هستند.

برای کنترل دقیق، مانند نمایش یک spinner بارگذاری فقط زمانی که پایگاه داده محلی خالی است و همگام‌سازی شبکه فعال است، مستقیماً درون composable خود به ویژگی‌های source و mediator دسترسی پیدا کنید.

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()
    }
}

واکنش به تغییرات وضعیت بارگذاری

ممکن است لازم باشد بر اساس تغییرات وضعیت بارگذاری، عوارض جانبی یک‌باره را فعال کنید، مانند اسکرول کردن به بالای لیست یا نمایش یک Snackbar پس از اتمام به‌روزرسانی.

snapshotFlow درون LaunchedEffect برای مشاهده تغییرات حالت به صورت یک جریان استفاده کنید. این به شما امکان می‌دهد عملگرهای استاندارد Flow مانند filter و distinctUntilChanged را برای جداسازی رویدادهای خاص اعمال کنید.

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)
    }
}

منابع اضافی

برای اطلاعات بیشتر در مورد کتابخانه Paging و وضعیت‌های بارگذاری، به منابع زیر مراجعه کنید.

مستندات

محتوا را مشاهده می‌کند

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}