Sayfalandırma kitaplığı, sayfa bölümü uygulanmış veriler için yükleme isteklerinin durumunu izler ve bunu LoadState
sınıfı aracılığıyla kullanıma sunar.
Uygulamanız, mevcut durum hakkında bilgi almak ve kullanıcı arayüzünü uygun şekilde güncellemek için PagingDataAdapter
'a bir işleyici kaydedebilir. Bu durumlar, kullanıcı arayüzü ile senkronize oldukları için adaptörden sağlanır.
Bu, sayfa yüklemesi kullanıcı arayüzüne uygulandığında işleyicinizin güncelleme aldığı anlamına gelir.
Her bir LoadType
ve veri kaynağı türü (PagingSource
veya RemoteMediator
) için ayrı bir LoadState
sinyali sağlanır. İşleyici tarafından sağlanan CombinedLoadStates
nesnesi, tüm bu sinyallerin yükleme durumu hakkında bilgi verir. Bu ayrıntılı bilgileri, kullanıcılarınıza uygun yükleme göstergeleri göstermek için kullanabilirsiniz.
Yükleme durumları
Sayfalama kitaplığı, yükleme durumunu LoadState
nesnesi aracılığıyla kullanıcı arayüzünde kullanılmak üzere gösterir. LoadState
nesneleri, geçerli yükleme durumuna bağlı olarak üç biçimden birinde olur:
- Etkin yükleme işlemi ve hata yoksa
LoadState
,LoadState.NotLoading
nesnesidir. Bu alt sınıf, sayfalara ayırma işleminin sonuna ulaşıp ulaşmadığını belirtenendOfPaginationReached
özelliğini de içerir. - Etkin bir yükleme işlemi varsa
LoadState
,LoadState.Loading
nesnesidir. - Hata varsa
LoadState
,LoadState.Error
nesnesidir.
Kullanıcı arayüzünüzde LoadState
kullanmanın iki yolu vardır: bir işleyici kullanmak veya yükleme durumunu doğrudan RecyclerView
listesinde sunmak için özel bir liste adaptörü kullanmak.
İşleyici ile yükleme durumuna erişme
Kullanıcı arayüzünüzde genel kullanım için yükleme durumunu almak üzere loadStateFlow
akışını veya PagingDataAdapter
tarafından sağlanan addLoadStateListener()
yöntemini kullanın. Bu mekanizmalar, her bir yükleme türünün LoadState
davranışı hakkında bilgi içeren bir CombinedLoadStates
nesnesine erişim sağlar.
Aşağıdaki örnekte PagingDataAdapter
, yenileme yükünün mevcut durumuna bağlı olarak farklı kullanıcı arayüzü bileşenleri görüntüler:
Kotlin
// 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 } }
Java
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); });
Java
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
hakkında daha fazla bilgi için Ek yükleme durumu bilgilerine erişme konusuna bakın.
Yükleme durumunu bir adaptörle gösterme
Sayfalandırma kitaplığı, yükleme durumunu doğrudan sayfalandırılmış veriler listesinde sunmak amacıyla LoadStateAdapter
adlı başka bir liste bağdaştırıcısı sağlar. Bu bağdaştırıcı, listenin geçerli yükleme durumuna erişim sağlar. Bu durumu, bilgileri görüntüleyen özel bir görünüm sahibine iletebilirsiniz.
Öncelikle, yükleme ve hata görünümlerine referansları ekranınızda tutan bir görüntüleme sahibi sınıfı oluşturun. LoadState
parametresini parametre olarak kabul eden bir bind()
işlevi oluşturun. Bu işlev, görünüm görünürlüğünü yükleme durumu parametresine göre değiştirmelidir:
Kotlin
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 } }
Java
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); } }
Java
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); } }
Ardından, LoadStateAdapter
uygulayan bir sınıf oluşturup onCreateViewHolder()
ve onBindViewHolder()
yöntemlerini tanımlayın. Bu yöntemler özel görünüm sahibinizin bir örneğini oluşturur ve ilişkili yükleme durumunu bağlar.
Kotlin
// 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) }
Java
// 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); } }
Java
// 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); } }
Yükleme durumunu üstbilgi veya altbilgi olarak görüntüleme
Yükleme ilerleme durumunu bir üst bilgi ve alt bilgide görüntülemek için PagingDataAdapter
nesnenizden withLoadStateHeaderAndFooter()
yöntemini çağırın:
Kotlin
pagingAdapter .withLoadStateHeaderAndFooter( header = ExampleLoadStateAdapter(adapter::retry), footer = ExampleLoadStateAdapter(adapter::retry) )
Java
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
Java
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
RecyclerView
listesinin yükleme durumunu yalnızca üstbilgide veya yalnızca altbilgide göstermesini istiyorsanız bunun yerine withLoadStateHeader()
veya withLoadStateFooter()
yöntemini çağırabilirsiniz.
Yükleme durumu ile ilgili ek bilgilere erişme
PagingDataAdapter
alanındaki CombinedLoadStates
nesnesi, PagingSource
ve varsa RemoteMediator
uygulamanız için yükleme durumları hakkında bilgi sağlar.
Kolaylık sağlaması açısından, CombinedLoadStates
ile ilgili refresh
, append
ve prepend
özelliklerini kullanarak uygun yükleme türü için bir LoadState
nesnesine erişebilirsiniz. Bu özellikler, varsa genellikle RemoteMediator
uygulamasındaki yükleme durumunu temel alır; aksi takdirde PagingSource
uygulamasından uygun yükleme durumunu içerir. Temel mantık hakkında daha ayrıntılı bilgi edinmek için CombinedLoadStates
referans belgelerine göz atın.
Kotlin
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 } }
Java
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; });
Java
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; });
Ancak yalnızca PagingSource
yükleme durumlarının kullanıcı arayüzü güncellemeleriyle senkronize edilmesinin garanti edildiğini unutmayın. refresh
, append
ve prepend
özellikleri yükleme durumunu PagingSource
veya RemoteMediator
değerlerinden alabildiği için kullanıcı arayüzü güncellemeleriyle senkronize olacakları garanti edilmez. Bu durum, yeni veriler kullanıcı arayüzüne eklenmeden önce yüklemenin bitmiş gibi göründüğü kullanıcı arayüzü sorunlarına neden olabilir.
Bu nedenle, kolaylık erişimcileri yük durumunu bir üstbilgi veya altbilgide görüntülemek için iyi bir şekilde çalışır, ancak diğer kullanım alanları için yükleme durumuna özel olarak PagingSource
veya RemoteMediator
üzerinden erişmeniz gerekebilir. CombinedLoadStates
, bu amaç için source
ve mediator
özelliklerini sağlar. Bu özelliklerin her biri, PagingSource
veya RemoteMediator
için LoadState
nesnelerini içeren bir LoadStates
nesnesini sırasıyla gösterir:
Kotlin
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 } }
Java
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; });
Java
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'teki zincir operatörleri
CombinedLoadStates
nesnesi yük durumundaki tüm değişikliklere erişim sağladığından yük durumu akışını belirli etkinliklere göre filtrelemek önemlidir. Bu, kesintilerden ve gereksiz kullanıcı arayüzü güncellemelerinden kaçınmak için kullanıcı arayüzünüzü uygun zamanda güncellemenizi sağlar.
Örneğin, yalnızca ilk veri yüklemesi tamamlandıktan sonra boş bir görünüm görüntülemek istediğinizi varsayalım. Bu kullanım alanı, bir veri yenileme yüklemesinin başladığını doğrulamanızı ve ardından yenilemenin tamamlandığını onaylamak için NotLoading
durumunu beklemenizi gerektirir. İhtiyacınız olanlar dışındaki tüm sinyalleri filtrelemeniz gerekir:
Kotlin
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) } }
Java
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); });
Java
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); } });
Bu örnek, yenileme yükleme durumunun güncellenmesini bekler ancak yalnızca durum NotLoading
olduğunda tetiklenir. Bu, herhangi bir kullanıcı arayüzü güncellemesi yapılmadan önce uzaktan yenilemenin tamamen bitmesini sağlar.
Stream API'leri bu tür işlemleri mümkün kılar. Uygulamanız, ihtiyaç duyduğu yükleme etkinliklerini belirtebilir ve uygun ölçütler karşılandığında yeni verileri işleyebilir.
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken gösterilir
- Sayfalı verileri yükleme ve görüntüleme
- Ağ ve veritabanı sayfası
- Çağrı kitaplığına genel bakış