পরিচালনা করুন এবং লোডিং অবস্থা উপস্থাপন করুন

পেজিং লাইব্রেরি পেজ করা ডেটার লোড অনুরোধের অবস্থা ট্র্যাক করে এবং LoadState ক্লাসের মাধ্যমে তা প্রকাশ করে।

প্রতিটি LoadType এবং ডেটা সোর্স টাইপের ( PagingSource অথবা RemoteMediator ) জন্য একটি পৃথক LoadState সিগন্যাল প্রদান করা হয়। লিসেনার দ্বারা প্রদত্ত CombinedLoadStates অবজেক্টটি এই সমস্ত সিগন্যাল থেকে লোডিং অবস্থা সম্পর্কে তথ্য সরবরাহ করে। আপনি এই বিস্তারিত তথ্য ব্যবহার করে আপনার ব্যবহারকারীদের কাছে উপযুক্ত লোডিং ইন্ডিকেটরগুলো প্রদর্শন করতে পারেন।

লোড হওয়ার অবস্থা

পেজিং লাইব্রেরি LoadState অবজেক্টের মাধ্যমে UI-তে ব্যবহারের জন্য লোডিং অবস্থা প্রকাশ করে। বর্তমান লোডিং অবস্থার উপর নির্ভর করে LoadState অবজেক্টগুলো তিনটি রূপের মধ্যে যেকোনো একটি গ্রহণ করে:

  • যদি কোনো সক্রিয় লোড অপারেশন না থাকে এবং কোনো ত্রুটিও না থাকে, তাহলে LoadState একটি LoadState.NotLoading অবজেক্ট হয়। এই সাবক্লাসটিতে endOfPaginationReached প্রপার্টিটিও অন্তর্ভুক্ত রয়েছে, যা নির্দেশ করে যে পেজিনেশনের শেষ প্রান্তে পৌঁছানো হয়েছে কিনা।
  • যদি কোনো সক্রিয় লোড অপারেশন থাকে, তাহলে LoadState হলো একটি LoadState.Loading অবজেক্ট।
  • যদি কোনো ত্রুটি থাকে, তাহলে LoadState একটি LoadState.Error অবজেক্ট হবে।

আপনার LazyPagingItems র‍্যাপারের loadState প্রপার্টির মাধ্যমে এই স্টেটগুলো অ্যাক্সেস করুন। আপনি এই স্টেটটি দুটি উপায়ে ব্যবহার করতে পারেন: মূল কন্টেন্টের দৃশ্যমানতা নিয়ন্ত্রণ করতে (যেমন একটি ফুল-স্ক্রিন রিফ্রেশ স্পিনার) অথবা সরাসরি আপনার LazyColumn স্ট্রিমে লোডিং আইটেম যুক্ত করতে (যেমন একটি ফুটার স্পিনার)।

একটি লিসেনারের মাধ্যমে লোডিং অবস্থা অ্যাক্সেস করুন

আপনার UI-এর লোডিং অবস্থা নিরীক্ষণ করতে, LazyPagingItems র‍্যাপার দ্বারা প্রদত্ত loadState প্রপার্টিটি ব্যবহার করুন। এটি একটি CombinedLoadStates অবজেক্ট রিটার্ন করে, যা আপনাকে রিফ্রেশ, অ্যাপেন্ড বা প্রিপেন্ড ইভেন্টের মাধ্যমে লোডিং আচরণের প্রতিক্রিয়া জানাতে সাহায্য করে।

নিম্নলিখিত উদাহরণে, রিফ্রেশ (প্রাথমিক) লোডের বর্তমান অবস্থার উপর নির্ভর করে UI একটি লোডিং স্পিনার বা একটি ত্রুটির বার্তা প্রদর্শন করে:

@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 সম্পর্কে আরও তথ্যের জন্য, Large data-sets (paging) দেখুন।

আপনার তালিকার শুরুতে বা শেষে লোডিং ইন্ডিকেটর (হেডার বা ফুটার হিসেবে) প্রদর্শন করতে, আপনার LazyColumn স্কোপের মধ্যে নির্দিষ্টভাবে সেই অবস্থাগুলোর জন্য ডেডিকেটেড আইটেম ব্লক যোগ করুন।

আপনি CombinedLoadStates অবজেক্টটি ব্যবহার করে হেডারের প্রিপেন্ড অবস্থা এবং ফুটারের অ্যাপেন্ড অবস্থা পর্যবেক্ষণ করতে পারেন।

নিচের উদাহরণে, আরও ডেটা আনার সময় তালিকার নীচে একটি প্রোগ্রেস বার বা রিট্রাই বাটন দেখানো হয়:

@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 ) থেকে লোড করার মধ্যেকার পার্থক্যকে অস্পষ্ট করে দেয়। এর ফলে, ক্যাশ করা ডেটা তাৎক্ষণিকভাবে উপলব্ধ থাকা সত্ত্বেও UI-তে ক্ষণিকের জন্য একটি লোডিং স্পিনার দেখা যেতে পারে।

সুনির্দিষ্ট নিয়ন্ত্রণের জন্য, যেমন শুধুমাত্র স্থানীয় ডেটাবেস খালি থাকলে এবং নেটওয়ার্ক সিঙ্ক সক্রিয় থাকলেই লোডিং স্পিনার দেখানোর জন্য, আপনার কম্পোজেবলের মধ্যে সরাসরি 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 দেখানো।

একটি LaunchedEffect ভিতরে snapshotFlow ব্যবহার করে স্ট্রিম হিসেবে অবস্থার পরিবর্তন পর্যবেক্ষণ করুন। এটি আপনাকে নির্দিষ্ট ইভেন্টগুলোকে আলাদা করতে filter এবং distinctUntilChanged মতো সাধারণ Flow অপারেটরগুলো প্রয়োগ করার সুযোগ দেয়।

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

অতিরিক্ত সম্পদ

পেজিং লাইব্রেরি এবং লোডিং অবস্থা সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত উৎসসমূহ দেখুন।

ডকুমেন্টেশন

বিষয়বস্তু দেখুন

{% হুবহু %} {% endverbatim %} {% হুবহু %} {% endverbatim %}