পেজিং লাইব্রেরি পেজড ডেটার জন্য লোড অনুরোধের অবস্থা ট্র্যাক করে এবং LoadState
ক্লাসের মাধ্যমে তা প্রকাশ করে। আপনার অ্যাপ বর্তমান অবস্থা সম্পর্কে তথ্য পেতে এবং সেই অনুযায়ী UI আপডেট করতে PagingDataAdapter
সাথে একজন শ্রোতাকে নিবন্ধন করতে পারে। এই অবস্থাগুলি অ্যাডাপ্টার থেকে সরবরাহ করা হয়েছে কারণ তারা UI এর সাথে সিঙ্ক্রোনাস। এর মানে হল যে আপনার শ্রোতা আপডেটগুলি পায় যখন পৃষ্ঠা লোড UI এ প্রয়োগ করা হয়।
প্রতিটি LoadType
এবং ডেটা সোর্স টাইপের জন্য একটি পৃথক LoadState
সংকেত প্রদান করা হয় (হয় PagingSource
বা RemoteMediator
)। শ্রোতা দ্বারা প্রদত্ত CombinedLoadStates
অবজেক্ট এই সমস্ত সংকেত থেকে লোডিং অবস্থা সম্পর্কে তথ্য প্রদান করে। আপনি আপনার ব্যবহারকারীদের উপযুক্ত লোডিং সূচকগুলি প্রদর্শন করতে এই বিস্তারিত তথ্য ব্যবহার করতে পারেন।
লোড হচ্ছে রাজ্য
পেজিং লাইব্রেরি LoadState
অবজেক্টের মাধ্যমে UI-তে ব্যবহারের জন্য লোডিং অবস্থা প্রকাশ করে। LoadState
অবজেক্টগুলি বর্তমান লোডিং অবস্থার উপর নির্ভর করে তিনটি ফর্মের একটি গ্রহণ করে:
- যদি কোন সক্রিয় লোড অপারেশন না থাকে এবং কোন ত্রুটি না থাকে, তাহলে
LoadState
হল একটিLoadState.NotLoading
অবজেক্ট। এই সাবক্লাসটিতেendOfPaginationReached
প্রপার্টিও রয়েছে, যা নির্দেশ করে যে পেজিনেশন শেষ হয়েছে কিনা। - যদি একটি সক্রিয় লোড অপারেশন থাকে, তাহলে
LoadState
একটিLoadState.Loading
অবজেক্ট। - যদি একটি ত্রুটি থাকে, তাহলে
LoadState
একটিLoadState.Error
অবজেক্ট।
আপনার UI-তে LoadState
ব্যবহার করার দুটি উপায় রয়েছে: একটি শ্রোতা ব্যবহার করে, অথবা RecyclerView
তালিকায় সরাসরি লোডিং অবস্থা উপস্থাপন করতে একটি বিশেষ তালিকা অ্যাডাপ্টার ব্যবহার করে৷
শ্রোতার সাথে লোডিং অবস্থা অ্যাক্সেস করুন
আপনার UI-তে সাধারণ ব্যবহারের জন্য লোডিং অবস্থা পেতে, আপনার PagingDataAdapter
দ্বারা প্রদত্ত loadStateFlow
স্ট্রীম বা addLoadStateListener()
পদ্ধতি ব্যবহার করুন। এই প্রক্রিয়াগুলি একটি CombinedLoadStates
অবজেক্টে অ্যাক্সেস প্রদান করে যাতে প্রতিটি লোডের প্রকারের জন্য LoadState
আচরণ সম্পর্কে তথ্য অন্তর্ভুক্ত থাকে।
নিম্নলিখিত উদাহরণে, PagingDataAdapter
রিফ্রেশ লোডের বর্তমান অবস্থার উপর নির্ভর করে বিভিন্ন UI উপাদান প্রদর্শন করে:
কোটলিন
// Activities can use lifecycleScope directly, but Fragments should instead use // viewLifecycleOwner.lifecycleScope. lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> progressBar.isVisible = loadStates.refresh is LoadState.Loading retry.isVisible = loadState.refresh !is LoadState.Loading errorMsg.isVisible = loadState.refresh is LoadState.Error } }
জাভা
pagingAdapter.addLoadStateListener(loadStates -> { progressBar.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.VISIBLE : View.GONE); retry.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.GONE : View.VISIBLE); errorMsg.setVisibility(loadStates.refresh instanceof LoadState.Error ? View.VISIBLE : View.GONE); });
জাভা
pagingAdapter.addLoadStateListener(loadStates -> { progressBar.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.VISIBLE : View.GONE); retry.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.GONE : View.VISIBLE); errorMsg.setVisibility(loadStates.refresh instanceof LoadState.Error ? View.VISIBLE : View.GONE); });
CombinedLoadStates
সম্পর্কে আরও তথ্যের জন্য, অতিরিক্ত লোডিং অবস্থার তথ্য অ্যাক্সেস করুন দেখুন।
একটি অ্যাডাপ্টারের সাথে লোডিং অবস্থা উপস্থাপন করুন
পেজিং লাইব্রেরি LoadStateAdapter
অ্যাডাপ্টার নামক আরেকটি তালিকা অ্যাডাপ্টার প্রদান করে যাতে পেজড ডেটার প্রদর্শিত তালিকায় সরাসরি লোডিং অবস্থা উপস্থাপন করা হয়। এই অ্যাডাপ্টারটি তালিকার বর্তমান লোড অবস্থায় অ্যাক্সেস প্রদান করে, যা আপনি একটি কাস্টম ভিউ হোল্ডারের কাছে পাঠাতে পারেন যা তথ্য প্রদর্শন করে।
প্রথমে, একটি ভিউ হোল্ডার ক্লাস তৈরি করুন যা আপনার স্ক্রিনে লোডিং এবং ত্রুটির দৃশ্যের রেফারেন্স রাখে। একটি bind()
ফাংশন তৈরি করুন যা একটি LoadState
একটি প্যারামিটার হিসাবে গ্রহণ করে। এই ফাংশনটি লোড স্টেট প্যারামিটারের উপর ভিত্তি করে ভিউ দৃশ্যমানতা টগল করা উচিত:
কোটলিন
class LoadStateViewHolder( parent: ViewGroup, retry: () -> Unit ) : RecyclerView.ViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.load_state_item, parent, false) ) { private val binding = LoadStateItemBinding.bind(itemView) private val progressBar: ProgressBar = binding.progressBar private val errorMsg: TextView = binding.errorMsg private val retry: Button = binding.retryButton .also { it.setOnClickListener { retry() } } fun bind(loadState: LoadState) { if (loadState is LoadState.Error) { errorMsg.text = loadState.error.localizedMessage } progressBar.isVisible = loadState is LoadState.Loading retry.isVisible = loadState is LoadState.Error errorMsg.isVisible = loadState is LoadState.Error } }
জাভা
class LoadStateViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; private TextView mErrorMsg; private Button mRetry; LoadStateViewHolder( @NonNull ViewGroup parent, @NonNull View.OnClickListener retryCallback) { super(LayoutInflater.from(parent.getContext()) .inflate(R.layout.load_state_item, parent, false)); LoadStateItemBinding binding = LoadStateItemBinding.bind(itemView); mProgressBar = binding.progressBar; mErrorMsg = binding.errorMsg; mRetry = binding.retryButton; } public void bind(LoadState loadState) { if (loadState instanceof LoadState.Error) { LoadState.Error loadStateError = (LoadState.Error) loadState; mErrorMsg.setText(loadStateError.getError().getLocalizedMessage()); } mProgressBar.setVisibility(loadState instanceof LoadState.Loading ? View.VISIBLE : View.GONE); mRetry.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); mErrorMsg.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); } }
জাভা
class LoadStateViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; private TextView mErrorMsg; private Button mRetry; LoadStateViewHolder( @NonNull ViewGroup parent, @NonNull View.OnClickListener retryCallback) { super(LayoutInflater.from(parent.getContext()) .inflate(R.layout.load_state_item, parent, false)); LoadStateItemBinding binding = LoadStateItemBinding.bind(itemView); mProgressBar = binding.progressBar; mErrorMsg = binding.errorMsg; mRetry = binding.retryButton; } public void bind(LoadState loadState) { if (loadState instanceof LoadState.Error) { LoadState.Error loadStateError = (LoadState.Error) loadState; mErrorMsg.setText(loadStateError.getError().getLocalizedMessage()); } mProgressBar.setVisibility(loadState instanceof LoadState.Loading ? View.VISIBLE : View.GONE); mRetry.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); mErrorMsg.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); } }
এর পরে, একটি ক্লাস তৈরি করুন যা LoadStateAdapter
প্রয়োগ করে, এবং onCreateViewHolder()
এবং onBindViewHolder()
পদ্ধতিগুলি সংজ্ঞায়িত করে। এই পদ্ধতিগুলি আপনার কাস্টম ভিউ হোল্ডারের একটি উদাহরণ তৈরি করে এবং সংশ্লিষ্ট লোড অবস্থাকে আবদ্ধ করে।
কোটলিন
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter( private val retry: () -> Unit ) : LoadStateAdapter<LoadStateViewHolder>() { override fun onCreateViewHolder( parent: ViewGroup, loadState: LoadState ) = LoadStateViewHolder(parent, retry) override fun onBindViewHolder( holder: LoadStateViewHolder, loadState: LoadState ) = holder.bind(loadState) }
জাভা
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter extends LoadStateAdapter<LoadStateViewHolder> { private View.OnClickListener mRetryCallback; ExampleLoadStateAdapter(View.OnClickListener retryCallback) { mRetryCallback = retryCallback; } @NotNull @Override public LoadStateViewHolder onCreateViewHolder(@NotNull ViewGroup parent, @NotNull LoadState loadState) { return new LoadStateViewHolder(parent, mRetryCallback); } @Override public void onBindViewHolder(@NotNull LoadStateViewHolder holder, @NotNull LoadState loadState) { holder.bind(loadState); } }
জাভা
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter extends LoadStateAdapter<LoadStateViewHolder> { private View.OnClickListener mRetryCallback; ExampleLoadStateAdapter(View.OnClickListener retryCallback) { mRetryCallback = retryCallback; } @NotNull @Override public LoadStateViewHolder onCreateViewHolder(@NotNull ViewGroup parent, @NotNull LoadState loadState) { return new LoadStateViewHolder(parent, mRetryCallback); } @Override public void onBindViewHolder(@NotNull LoadStateViewHolder holder, @NotNull LoadState loadState) { holder.bind(loadState); } }
হেডার বা ফুটার হিসাবে লোডিং অবস্থা প্রদর্শন করুন
একটি শিরোনাম এবং একটি ফুটারে লোডিং অগ্রগতি প্রদর্শন করতে, আপনার PagingDataAdapter
অবজেক্ট থেকে withLoadStateHeaderAndFooter()
পদ্ধতিতে কল করুন:
কোটলিন
pagingAdapter .withLoadStateHeaderAndFooter( header = ExampleLoadStateAdapter(adapter::retry), footer = ExampleLoadStateAdapter(adapter::retry) )
জাভা
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
জাভা
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
আপনি পরিবর্তে withLoadStateHeader()
অথবা withLoadStateFooter()
কল করতে পারেন যদি আপনি RecyclerView
তালিকাটি শুধুমাত্র হেডারে বা শুধুমাত্র ফুটারে লোডিং অবস্থা প্রদর্শন করতে চান।
অতিরিক্ত লোডিং অবস্থার তথ্য অ্যাক্সেস করুন
PagingDataAdapter
থেকে CombinedLoadStates
অবজেক্ট আপনার PagingSource
বাস্তবায়নের জন্য লোড স্টেট এবং আপনার RemoteMediator
বাস্তবায়নের জন্য তথ্য প্রদান করে, যদি একটি বিদ্যমান থাকে।
সুবিধার জন্য, আপনি উপযুক্ত লোড ধরনের জন্য একটি LoadState
অবজেক্ট অ্যাক্সেস করতে CombinedLoadStates
থেকে refresh
, append
, এবং prepend
বৈশিষ্ট্যগুলি ব্যবহার করতে পারেন। এই বৈশিষ্ট্যগুলি সাধারণত RemoteMediator
বাস্তবায়ন থেকে লোড অবস্থার দিকে অগ্রসর হয় যদি একটি বিদ্যমান থাকে; অন্যথায়, তারা PagingSource
বাস্তবায়ন থেকে উপযুক্ত লোড অবস্থা ধারণ করে। অন্তর্নিহিত যুক্তি সম্পর্কে আরও বিস্তারিত তথ্যের জন্য, CombinedLoadStates
এর জন্য রেফারেন্স ডকুমেন্টেশন দেখুন।
কোটলিন
lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. refreshLoadState: LoadState = loadStates.refresh // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. prependLoadState: LoadState = loadStates.prepend // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. appendLoadState: LoadState = loadStates.append } }
জাভা
pagingAdapter.addLoadStateListener(loadStates -> { // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState refreshLoadState = loadStates.refresh; // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState prependLoadState = loadStates.prepend; // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState appendLoadState = loadStates.append; });
জাভা
pagingAdapter.addLoadStateListener(loadStates -> { // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState refreshLoadState = loadStates.refresh; // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState prependLoadState = loadStates.prepend; // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState appendLoadState = loadStates.append; });
যাইহোক, এটা মনে রাখা গুরুত্বপূর্ণ যে শুধুমাত্র PagingSource
লোড স্টেটগুলি UI আপডেটের সাথে সিঙ্ক্রোনাস হওয়ার নিশ্চয়তা রয়েছে৷ যেহেতু refresh
, append
এবং prepend
বৈশিষ্ট্যগুলি সম্ভাব্যভাবে PagingSource
বা RemoteMediator
থেকে লোডের অবস্থা নিতে পারে, সেগুলি UI আপডেটের সাথে সিঙ্ক্রোনাস হওয়ার নিশ্চয়তা নেই৷ এটি UI সমস্যার কারণ হতে পারে যেখানে UI-তে নতুন ডেটা যোগ করার আগে লোডিং শেষ হয়ে গেছে।
এই কারণে, সুবিধার অ্যাক্সেসরগুলি শিরোনাম বা ফুটারে লোড অবস্থা প্রদর্শনের জন্য ভাল কাজ করে, তবে অন্যান্য ব্যবহারের ক্ষেত্রে আপনাকে বিশেষভাবে PagingSource
বা RemoteMediator
থেকে লোড অবস্থা অ্যাক্সেস করতে হতে পারে। CombinedLoadStates
এই উদ্দেশ্যে source
এবং mediator
বৈশিষ্ট্য প্রদান করে। এই বৈশিষ্ট্যগুলি প্রতিটি একটি LoadStates
অবজেক্টকে প্রকাশ করে যাতে যথাক্রমে PagingSource
বা RemoteMediator
জন্য LoadState
অবজেক্ট থাকে:
কোটলিন
lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> // Directly access the RemoteMediator refresh load state. mediatorRefreshLoadState: LoadState? = loadStates.mediator.refresh // Directly access the RemoteMediator append load state. mediatorAppendLoadState: LoadState? = loadStates.mediator.append // Directly access the RemoteMediator prepend load state. mediatorPrependLoadState: LoadState? = loadStates.mediator.prepend // Directly access the PagingSource refresh load state. sourceRefreshLoadState: LoadState = loadStates.source.refresh // Directly access the PagingSource append load state. sourceAppendLoadState: LoadState = loadStates.source.append // Directly access the PagingSource prepend load state. sourcePrependLoadState: LoadState = loadStates.source.prepend } }
জাভা
pagingAdapter.addLoadStateListener(loadStates -> { // Directly access the RemoteMediator refresh load state. LoadState mediatorRefreshLoadState = loadStates.mediator.refresh; // Directly access the RemoteMediator append load state. LoadState mediatorAppendLoadState = loadStates.mediator.append; // Directly access the RemoteMediator prepend load state. LoadState mediatorPrependLoadState = loadStates.mediator.prepend; // Directly access the PagingSource refresh load state. LoadState sourceRefreshLoadState = loadStates.source.refresh; // Directly access the PagingSource append load state. LoadState sourceAppendLoadState = loadStates.source.append; // Directly access the PagingSource prepend load state. LoadState sourcePrependLoadState = loadStates.source.prepend; });
জাভা
pagingAdapter.addLoadStateListener(loadStates -> { // Directly access the RemoteMediator refresh load state. LoadState mediatorRefreshLoadState = loadStates.mediator.refresh; // Directly access the RemoteMediator append load state. LoadState mediatorAppendLoadState = loadStates.mediator.append; // Directly access the RemoteMediator prepend load state. LoadState mediatorPrependLoadState = loadStates.mediator.prepend; // Directly access the PagingSource refresh load state. LoadState sourceRefreshLoadState = loadStates.source.refresh; // Directly access the PagingSource append load state. LoadState sourceAppendLoadState = loadStates.source.append; // Directly access the PagingSource prepend load state. LoadState sourcePrependLoadState = loadStates.source.prepend; });
LoadState এ চেইন অপারেটর
যেহেতু CombinedLoadStates
অবজেক্ট লোড অবস্থায় সমস্ত পরিবর্তনের অ্যাক্সেস প্রদান করে, তাই নির্দিষ্ট ইভেন্টের উপর ভিত্তি করে লোড স্টেট স্ট্রীম ফিল্টার করা গুরুত্বপূর্ণ। এটি নিশ্চিত করে যে আপনি তোতলামি এবং অপ্রয়োজনীয় UI আপডেট এড়াতে উপযুক্ত সময়ে আপনার UI আপডেট করবেন।
উদাহরণস্বরূপ, ধরুন আপনি একটি খালি দৃশ্য প্রদর্শন করতে চান, তবে প্রাথমিক ডেটা লোড সম্পূর্ণ হওয়ার পরেই। এই ব্যবহারের ক্ষেত্রে আপনাকে যাচাই করতে হবে যে একটি ডেটা রিফ্রেশ লোড শুরু হয়েছে, তারপর রিফ্রেশ সম্পূর্ণ হয়েছে তা নিশ্চিত করার জন্য NotLoading
অবস্থার জন্য অপেক্ষা করুন। আপনার প্রয়োজন ব্যতীত আপনাকে অবশ্যই সমস্ত সংকেত ফিল্টার করতে হবে:
কোটলিন
lifecycleScope.launchWhenCreated { adapter.loadStateFlow // Only emit when REFRESH LoadState for RemoteMediator changes. .distinctUntilChangedBy { it.refresh } // Only react to cases where REFRESH completes, such as NotLoading. .filter { it.refresh is LoadState.NotLoading } // Scroll to top is synchronous with UI updates, even if remote load was // triggered. .collect { binding.list.scrollToPosition(0) } }
জাভা
PublishSubject<CombinedLoadStates> subject = PublishSubject.create(); Disposable disposable = subject.distinctUntilChanged(CombinedLoadStates::getRefresh) .filter( combinedLoadStates -> combinedLoadStates.getRefresh() instanceof LoadState.NotLoading) .subscribe(combinedLoadStates -> binding.list.scrollToPosition(0)); pagingAdapter.addLoadStateListener(loadStates -> { subject.onNext(loadStates); });
জাভা
LiveData<CombinedLoadStates> liveData = new MutableLiveData<>(); LiveData<LoadState> refreshLiveData = Transformations.map(liveData, CombinedLoadStates::getRefresh); LiveData<LoadState> distinctLiveData = Transformations.distinctUntilChanged(refreshLiveData); distinctLiveData.observeForever(loadState -> { if (loadState instanceof LoadState.NotLoading) { binding.list.scrollToPosition(0); } });
এই উদাহরণটি রিফ্রেশ লোড স্টেট আপডেট না হওয়া পর্যন্ত অপেক্ষা করে, কিন্তু শুধুমাত্র যখন স্টেট NotLoading
হয় তখনই ট্রিগার হয়। এটি নিশ্চিত করে যে কোনও UI আপডেট হওয়ার আগে রিমোট রিফ্রেশ সম্পূর্ণভাবে শেষ হয়েছে।
স্ট্রিম API এই ধরনের অপারেশন সম্ভব করে তোলে। আপনার অ্যাপটি প্রয়োজনীয় লোড ইভেন্টগুলি নির্দিষ্ট করতে পারে এবং উপযুক্ত মানদণ্ড পূরণ হলে নতুন ডেটা পরিচালনা করতে পারে৷
{% শব্দার্থে %}আপনার জন্য প্রস্তাবিত
- দ্রষ্টব্য: জাভাস্ক্রিপ্ট বন্ধ থাকলে লিঙ্ক টেক্সট প্রদর্শিত হয়
- পৃষ্ঠাযুক্ত ডেটা লোড এবং প্রদর্শন করুন
- নেটওয়ার্ক এবং ডাটাবেস থেকে পৃষ্ঠা
- পেজিং লাইব্রেরি ওভারভিউ