کتابخانه Paging وضعیت درخواستهای بارگذاری برای دادههای صفحهبندی شده را ردیابی میکند و آنها را از طریق کلاس LoadState
نمایش میدهد. برنامه شما میتواند شنوندهای را با PagingDataAdapter
ثبت کند تا اطلاعاتی در مورد وضعیت فعلی دریافت کند و رابط کاربری را متناسب با آن بهروزرسانی کند. این حالت ها از آداپتور ارائه می شوند زیرا با رابط کاربری همگام هستند. این به این معنی است که شنونده شما بهروزرسانیها را زمانی که بارگذاری صفحه در UI اعمال میشود، دریافت میکند.
یک سیگنال LoadState
جداگانه برای هر LoadType
و نوع منبع داده (اعم از PagingSource
یا RemoteMediator
) ارائه می شود. شی CombinedLoadStates
ارائه شده توسط شنونده اطلاعاتی در مورد وضعیت بارگذاری از تمام این سیگنال ها ارائه می دهد. شما می توانید از این اطلاعات دقیق برای نمایش شاخص های بارگذاری مناسب به کاربران خود استفاده کنید.
حالت های بارگیری
کتابخانه Paging وضعیت بارگیری را برای استفاده در UI از طریق شی LoadState
نشان می دهد. اشیاء LoadState
بسته به وضعیت بارگذاری فعلی یکی از سه شکل زیر را دارند:
- اگر عملیات بارگذاری فعال و خطا وجود نداشته باشد،
LoadState
یک شیLoadState.NotLoading
است. این زیر کلاس همچنین شامل ویژگیendOfPaginationReached
است که نشان می دهد آیا به پایان صفحه بندی رسیده است یا خیر. - اگر عملیات بارگذاری فعال وجود داشته باشد،
LoadState
یک شیLoadState.Loading
است. - اگر خطایی وجود داشته باشد،
LoadState
یک شیLoadState.Error
است.
دو راه برای استفاده از LoadState
در رابط کاربری وجود دارد: استفاده از شنونده، یا استفاده از یک آداپتور لیست ویژه برای ارائه وضعیت بارگیری مستقیماً در لیست RecyclerView
.
با شنونده به وضعیت بارگیری دسترسی پیدا کنید
برای دریافت حالت بارگیری برای استفاده عمومی در رابط کاربری خود، از جریان loadStateFlow
یا متد addLoadStateListener()
که توسط PagingDataAdapter
ارائه شده است استفاده کنید. این مکانیسم ها دسترسی به یک شی 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
، دسترسی به اطلاعات وضعیت بارگذاری اضافی را ببینید.
وضعیت بارگذاری را با یک آداپتور ارائه دهید
کتابخانه Paging آداپتور لیست دیگری به نام LoadStateAdapter
را به منظور ارائه وضعیت بارگیری مستقیماً در لیست نمایش داده شده از داده های صفحه شده ارائه می دهد. این آداپتور دسترسی به وضعیت بارگذاری فعلی لیست را فراهم می کند، که می توانید آن را به نگهدارنده نمایش سفارشی که اطلاعات را نمایش می دهد، منتقل کنید.
ابتدا یک کلاس نگهدارنده view ایجاد کنید که ارجاع به نمایش های بارگیری و خطا را روی صفحه شما نگه می دارد. یک bind()
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); } }
حالت بارگذاری را به صورت سرصفحه یا پاورقی نمایش دهید
برای نمایش پیشرفت بارگذاری در یک هدر و یک پاورقی، متد withLoadStateHeaderAndFooter()
را از شی PagingDataAdapter
خود فراخوانی کنید:
کاتلین
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));
اگر میخواهید فهرست RecyclerView
حالت بارگیری را فقط در سرصفحه یا فقط در پاورقی نمایش دهد، میتوانید با withLoadStateHeader()
یا withLoadStateFooter()
تماس بگیرید.
به اطلاعات اضافی وضعیت بارگیری دسترسی داشته باشید
شی CombinedLoadStates
از PagingDataAdapter
اطلاعاتی در مورد وضعیت های بارگذاری برای اجرای PagingSource
و همچنین برای اجرای RemoteMediator
شما، در صورت وجود، ارائه می دهد.
برای راحتی، می توانید از ویژگی های refresh
، append
و prepend
از CombinedLoadStates
برای دسترسی به یک شی LoadState
برای نوع بار مناسب استفاده کنید. این ویژگیها معمولاً در صورت وجود، به حالت بار از اجرای 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
با بهروزرسانیهای رابط کاربری همگام هستند. از آنجایی که ویژگی های refresh
، append
و prepend
به طور بالقوه می توانند وضعیت بارگذاری را از PagingSource
یا RemoteMediator
بگیرند، تضمینی برای همگام بودن آنها با به روز رسانی های UI وجود ندارد. این میتواند باعث ایجاد مشکلاتی در رابط کاربری شود که در آن به نظر میرسد بارگیری قبل از اضافه شدن هر یک از دادههای جدید به UI تمام میشود.
به همین دلیل، دسترسیهای راحت برای نمایش وضعیت بار در سرصفحه یا پاورقی به خوبی کار میکنند، اما برای سایر موارد استفاده ممکن است نیاز باشد که به طور خاص به وضعیت بارگذاری از طریق PagingSource
یا RemoteMediator
دسترسی داشته باشید. CombinedLoadStates
ویژگی های source
و mediator
را برای این منظور فراهم می کند. این ویژگی ها هر کدام یک شی LoadStates
را نشان می دهند که به ترتیب حاوی اشیاء LoadState
برای PagingSource
یا RemoteMediator
است:
کاتلین
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
باشد. این تضمین میکند که بهروزرسانی از راه دور قبل از انجام هر گونه بهروزرسانی رابط کاربری کاملاً به پایان رسیده است.
Stream API ها این نوع عملیات را ممکن می سازند. برنامه شما می تواند رویدادهای بار مورد نیاز خود را مشخص کند و در صورت رعایت معیارهای مناسب، داده های جدید را مدیریت کند.
{% کلمه به کلمه %}برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- بارگیری و نمایش داده های صفحه بندی شده
- صفحه از شبکه و پایگاه داده
- نمای کلی کتابخانه صفحهبندی