Yükleme durumlarını yönetme ve sunma

Sayfalandırma kitaplığı, sayfalandırılmış veriler için yükleme isteklerinin durumunu izler ve LoadState sınıfıyla karşılaştırabilirsiniz. Uygulamanız, PagingDataAdapter - geçerli durumla ilgili bilgi alıp kullanıcı arayüzünü buna göre güncelleyin. Bu durumları, kullanıcı arayüzüyle eşzamanlı olduğundan bağdaştırıcıdan sağlanır. Bu, sayfa yükleme işlemi tamamlandığında dinleyicinizin güncellemeleri aldığı anlamına gelir. uygulanmıştır.

Her biri için ayrı bir LoadState sinyali sağlanır LoadType ve veri kaynağı türü (PagingSource veya RemoteMediator) bulabilirsiniz. İlgili içeriği oluşturmak için kullanılan CombinedLoadStates dinleyici tarafından sağlanan nesne, yükleme durumu hakkında bilgi sağlar tüm bu sinyallerden yararlanır. Bu ayrıntılı bilgileri kullanarak ilgili yükleme göstergeleri sunun.

Durumlar yükleniyor

Sayfalandırma kitaplığı, yükleme durumunu LoadState nesne algılandı. LoadState nesne bağlı olarak üç biçimden birini alır mevcut yükleme durumu:

LoadState öğesini kullanıcı arayüzünüzde iki şekilde kullanabilirsiniz: bir işleyici veya yükleme durumunu doğrudan RecyclerView liste'ye dokunun.

İşleyiciyle yükleme durumuna erişme

Kullanıcı arayüzünüzde genel kullanım için yükleme durumunu öğrenmek üzere loadStateFlow akış veya addLoadStateListener() yöntemi (PagingDataAdapter) tarafından sağlanır. Bu mekanizmalar LoadState hakkında bilgi içeren bir CombinedLoadStates nesnesi ayrı ayrı belirleyebilirsiniz.

Aşağıdaki örnekte, PagingDataAdapter farklı bir kullanıcı arayüzü gösteriyor yenilenme yükünün mevcut durumuna bağlı olarak farklılık gösterir:

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 bkz. Ek yüklemeye erişim eyalet bilgilerini kontrol edin.

Yükleme durumunu bağdaştırıcıyla sunma

Sayfalama kitaplığı, Şu için LoadStateAdapter: bunun amacı, sayfalandırılmış görüntülenen listede doğrudan yükleme durumunu sunma dışı verilerdir. Bu bağdaştırıcı, listenin mevcut yükleme durumuna erişim sağlar. bilgileri görüntüleyen özel bir görünüm tutucuya geçirebilirsiniz.

Öncelikle, yükleme ve hataya verilen referansları tutan bir görünüm tutucu sınıfı oluşturun kaç kez görüntülendiğini gösterir. Şu olarak LoadState kabul eden bir bind() işlevi oluşturun: parametresinden sonra bir değer girin. Bu işlev, görünüm görünürlüğünü yüke göre değiştirmelidir durum parametresi:

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

Sonra, LoadStateAdapter uygulayan bir sınıf oluşturun ve onCreateViewHolder() ve onBindViewHolder() yöntemlerine göz atın. Bu yöntemler, özel görünüm sahibi ve bağlantınızın bir örneğini oluşturur ilgili yükleme durumudur.

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 ve altbilgide görüntülemek için withLoadStateHeaderAndFooter() yöntemini PagingDataAdapter nesnenizden kaldı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));

Bunun yerine şu numarayı arayabilirsiniz: withLoadStateHeader() veya withLoadStateFooter() RecyclerView listesinin yalnızca veya yalnızca altbilgiye ekleyin.

Ek yükleme durumu bilgilerine erişme

PagingDataAdapter konumundaki CombinedLoadStates nesnesi şunun hakkında bilgi sağlar: PagingSource uygulamanızın ve ayrıca Varsa RemoteMediator uygulaması.

Kolaylık olması için refresh append ve prepend mülkünün bir LoadState nesnesine erişmek için CombinedLoadStates uygun bir yükleme türü seçin. Bu özellikler genellikle varsa RemoteMediator uygulaması; Aksi takdirde, PagingSource uygulamasından uygun yükleme durumunu kontrol edin. Daha ayrıntılı daha fazla bilgi edinmek için referans belgelerine bakın. CombinedLoadStates.

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 durumunun göz önünde bulundurulması önemlidir. kullanıcı arayüzü güncellemeleriyle eşzamanlı olacağı garanti edilir. Çünkü refresh, append ve prepend mülkleri, yükleme durumunu şuradan alabilir: PagingSource veya RemoteMediator arasında geçiş yapılırsa kullanıcı arayüzü güncellemeleriyle senkronize edilir. Bu durum, yüklemenin göründüğü yerlerde kullanıcı arayüzü sorunlarına neden olabilir kullanıcı arayüzüne yeni veriler eklenmeden önce tamamlanması gerekir.

Bu nedenle, kolaylık sağlayan erişim araçları yükü iyi bir şekilde görüntüleyebilir. bunu bir üstbilgide veya altbilgide eklersiniz, ancak diğer kullanım alanları için yükleme durumuna özellikle PagingSource veya RemoteMediator. CombinedLoadStates, source ve mediator bu özellikleri kullanabilirsiniz. Bu özelliklerin her biri, LoadStates nesne PagingSource veya RemoteMediator için LoadState nesnelerini içerir oluşturmak için:

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'te zincir operatörleri

Çünkü CombinedLoadStates nesnesi, yükleme durumuna göre, yükleme durumu akışını belirli ölçütlere göre etkinlikler. Bu sayede kullanıcı arayüzünüzü, uygulama yükleme işleminden kaçınmak için uygun zamanda güncellemeniz gerekir. takılmalar ve gereksiz kullanıcı arayüzü güncellemeleri.

Örneğin, boş bir görünüm görüntülemek istediğinizi, ancak yalnızca yüklemenin tamamlanmasına yardımcı olur. Bu kullanım alanı, bir veri türünün yenileme yüklemesi başladı, ardından NotLoading durumunun onaylamasını bekleyin yenileme tamamlandı. Şunlar dışındaki tüm sinyalleri filtrelemeniz gerekir: ihtiyacınız olanlar:

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 durumu güncellenene kadar bekler, ancak yalnızca şu tetikleyicileri tetikler: eyalet NotLoading olduğunda. Bu şekilde, uzaktan yenileme işleminin kullanıcı arayüzü güncellemesi yapılmadan biter.

Akış API'leri bu tür işlemleri mümkün kılar. Uygulamanız yükü belirtebilir ve uygun ölçütler karşılandığında yeni verileri işler.

ziyaret edin.