कॉन्टेंट लोड होने की स्थितियों को मैनेज करना और प्रज़ेंट करना

पेजिंग लाइब्रेरी, पेज किए गए डेटा के लोड करने के अनुरोधों की स्थिति को ट्रैक करती है और इसे LoadState क्लास की मदद से किया गया है. आपका ऐप्लिकेशन, लिसनर को PagingDataAdapter से मौजूदा स्थिति के बारे में जानकारी पाएं और उसके हिसाब से यूज़र इंटरफ़ेस (यूआई) अपडेट करें. ये स्थितियों को अडैप्टर से लिया जाता है, क्योंकि वे यूज़र इंटरफ़ेस (यूआई) के साथ सिंक होती हैं. इसका मतलब है कि पेज लोड हो जाने के बाद, लिसनर को अपडेट मिलते हैं यूज़र इंटरफ़ेस (यूआई) पर लागू किया गया.

हर एक के लिए अलग LoadState सिग्नल दिया जाता है LoadType और डेटा सोर्स का टाइप (PagingSource या RemoteMediator). कॉन्टेंट बनाने CombinedLoadStates लिसनर से मिला ऑब्जेक्ट, लोड होने की स्थिति के बारे में जानकारी देता है इन सभी सिग्नलों से पता चलता है. आप इस विस्तृत जानकारी का उपयोग उपयोगकर्ता के लिए सही तरह के लोडिंग इंडिकेटर.

राज्यों के नाम लोड हो रहे हैं

पेजिंग लाइब्रेरी, यूज़र इंटरफ़ेस (यूआई) में इस्तेमाल की जाने वाली लोडिंग स्थिति को LoadState ऑब्जेक्ट. LoadState ऑब्जेक्ट तीन में से एक रूप लेता है. यह इस पर निर्भर करता है लोड होने की मौजूदा स्थिति:

  • अगर लोड करने की कोई कार्रवाई चालू नहीं है और कोई गड़बड़ी नहीं है, तो LoadState एक LoadState.NotLoading ऑब्जेक्ट है. इस सब-क्लास में ये भी शामिल हैं: endOfPaginationReached प्रॉपर्टी, जिससे पता चलता है कि पेज नंबर खत्म हुआ है या नहीं.
  • अगर लोड करने की कोई कार्रवाई चालू है, तो LoadState एक LoadState.Loading ऑब्जेक्ट है.
  • अगर कोई गड़बड़ी होती है, तो LoadState LoadState.Error ऑब्जेक्ट.

यूज़र इंटरफ़ेस (यूआई) में LoadState का इस्तेमाल करने के दो तरीके हैं: लिसनर का इस्तेमाल करना या विशेष सूची अडैप्टर, जो पेज लोड होने की स्थिति को सीधे RecyclerView सूची.

लिसनर की मदद से, कॉन्टेंट लोड होने की स्थिति को ऐक्सेस करें

अपने यूज़र इंटरफ़ेस (यूआई) में सामान्य इस्तेमाल के लिए, लोड होने की स्थिति जानने के लिए, loadStateFlow स्ट्रीम या addLoadStateListener() आपके PagingDataAdapter के ज़रिए उपलब्ध कराया गया तरीका है. इन तरीकों से, आपको एक CombinedLoadStates ऑब्जेक्ट, जिसमें LoadState के बारे में जानकारी शामिल है व्यवहार की जानकारी शामिल है.

नीचे दिए गए उदाहरण में, PagingDataAdapter अलग यूज़र इंटरफ़ेस (यूआई) दिखाता है रीफ़्रेश लोड की मौजूदा स्थिति के आधार पर कॉम्पोनेंट:

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 के बारे में ज़्यादा जानकारी के लिए, अतिरिक्त लोडिंग पेज ऐक्सेस करें राज्य की जानकारी.

अडैप्टर की मदद से, पेज लोड होने की स्थिति के बारे में बताएं

पेजिंग लाइब्रेरी से एक और लिस्ट अडैप्टर मिलता है, जिसे LoadStateAdapter इसका मकसद पेज पर लोड होने की स्थिति को सीधे पेज की गई सूची में दिखाना है डेटा शामिल है. यह अडैप्टर, सूची की मौजूदा लोड स्थिति को ऐक्सेस करने की सुविधा देता है, के पास ऐसे कस्टम व्यू होल्डर को पास किया जा सकता है जो जानकारी दिखाता है.

सबसे पहले, एक व्यू होल्डर क्लास बनाएं जिसमें लोड होने और गड़बड़ी के बारे में जानकारी मौजूद हो दृश्य आपकी स्क्रीन पर दिखाई देंगे. ऐसा bind() फ़ंक्शन बनाएं जो LoadState को पैरामीटर. इस फ़ंक्शन को लोड के हिसाब से, 'किसको दिखे' सेटिंग को टॉगल करना चाहिए स्थिति पैरामीटर:

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

इसके बाद, LoadStateAdapter को लागू करने वाली एक क्लास बनाएं और onCreateViewHolder() और onBindViewHolder() तरीकों का इस्तेमाल करना होगा. ये तरीके आपके कस्टम व्यू होल्डर का इंस्टेंस बनाते हैं और बाइंड करते हैं लोड होने की स्थिति के बारे में ज़्यादा जानें.

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

हेडर और फ़ुटर में लोड होने की स्थिति दिखाने के लिए, withLoadStateHeaderAndFooter() आपके PagingDataAdapter ऑब्जेक्ट से तरीका:

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

इसके बजाय, आप कॉल कर सकते हैं withLoadStateHeader() या withLoadStateFooter() यदि आप चाहते हैं कि RecyclerView सूची लोड होने की स्थिति केवल हेडर या सिर्फ़ फ़ुटर में.

लोड होने की स्थिति के बारे में ज़्यादा जानकारी ऐक्सेस करना

PagingDataAdapter का CombinedLoadStates ऑब्जेक्ट इन चीज़ों की जानकारी देता है आपके PagingSource को लागू करने के लिए और साथ ही आपके RemoteMediator लागू करने की सुविधा, अगर पहले से मौजूद हो.

सुविधा के लिए, refresh append, और prepend प्रॉपर्टी को CombinedLoadStates से इकट्ठा करने के लिए, LoadState ऑब्जेक्ट को ऐक्सेस किया जा सकता है लोड होने का सही तरीका चुनें. आम तौर पर ये प्रॉपर्टी, लोड होने की इस स्थिति से अगर पहले से मौजूद है, तो RemoteMediator लागू करना; नहीं तो, उनमें लागू करने से PagingSource की उचित लोड स्थिति होगी. ज़्यादा जानकारी के लिए इस्तेमाल किए जा सकने वाले लॉजिक के बारे में जानकारी पाने के लिए, 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;
});

हालांकि, यह याद रखना ज़रूरी है कि सिर्फ़ PagingSource लोड होने की स्थितियां इसकी गारंटी है कि ये यूज़र इंटरफ़ेस (यूआई) अपडेट के साथ सिंक होते रहेंगे. क्योंकि refresh, append और prepend प्रॉपर्टी, लोड होने की स्थिति PagingSource या RemoteMediator के लिए, उनके होने की कोई गारंटी नहीं है यूज़र इंटरफ़ेस (यूआई) अपडेट के साथ सिंक्रोनस होता है. इसकी वजह से, यूज़र इंटरफ़ेस (यूआई) में समस्याएं हो सकती हैं, जिनमें लोडिंग दिख रही हो ताकि यूज़र इंटरफ़ेस (यूआई) में कोई भी नया डेटा जोड़े जाने से पहले उसे पूरा कर लिया जाए.

इस वजह से, सुविधा ऐक्सेसर, लोड दिखाने के लिए सही तरीके से काम करते हैं फ़ाइल होती है, लेकिन अन्य उपयोग के मामलों में आपको लोड होने की स्थिति को खास तौर पर PagingSource से ऐक्सेस करें या RemoteMediator. CombinedLoadStates यह देता है source और mediator प्रॉपर्टी सेट अप की जा सकती हैं. ये प्रॉपर्टी LoadStates ऑब्जेक्ट जो इसमें PagingSource या RemoteMediator के लिए LoadState ऑब्जेक्ट हैं क्रमश:

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 पर चेन ऑपरेटर

क्योंकि CombinedLoadStates ऑब्जेक्ट, इसमें किए गए सभी बदलावों का ऐक्सेस देता है लोड स्थिति, लोड स्थिति स्ट्रीम इवेंट. इससे यह पक्का होता है कि आप अपने यूज़र इंटरफ़ेस (यूआई) को सही समय पर अपडेट करें, ताकि स्टटर और गैर-ज़रूरी यूज़र इंटरफ़ेस (यूआई) अपडेट.

उदाहरण के लिए, मान लें कि आप एक खाली दृश्य दिखाना चाहते हैं, लेकिन शुरुआती डेटा लोड पूरा होता है. इस्तेमाल के इस उदाहरण में, आपको यह पुष्टि करनी होगी कि रीफ़्रेश लोड हो गया है, इसके बाद NotLoading की स्थिति से इसकी पुष्टि होने का इंतज़ार करें रीफ़्रेश पूरा हो गया. आपको एक सिग्नल को छोड़कर, बाकी सभी सिग्नल को फ़िल्टर करना होगा आपको इनकी ज़रूरत होगी:

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

यह उदाहरण रीफ़्रेश लोड स्थिति के अपडेट होने तक इंतज़ार करता है, लेकिन यह केवल ट्रिगर होता है जब राज्य NotLoading हो. इससे यह पक्का होता है कि रिमोट रीफ़्रेश यूज़र इंटरफ़ेस (यूआई) के अपडेट होने से पहले ही पूरा किया जा सकता है.

स्ट्रीम एपीआई के लिए, यह काम किया जा सकता है. आपका ऐप्लिकेशन, लोड होने की जानकारी तय कर सकता है उन इवेंट को ट्रिगर करता है जिनकी उसे ज़रूरत होती है. साथ ही, ज़रूरी शर्तें पूरी होने पर नए डेटा को हैंडल करता है.