তথ্য স্ট্রীম রূপান্তর

আপনি যখন পৃষ্ঠাযুক্ত ডেটা নিয়ে কাজ করেন , তখন আপনাকে প্রায়ই ডেটা স্ট্রীমটি লোড করার সাথে সাথে রূপান্তর করতে হবে। উদাহরণস্বরূপ, আপনাকে আইটেমগুলির একটি তালিকা ফিল্টার করতে হতে পারে, বা আইটেমগুলিকে UI-তে উপস্থাপন করার আগে একটি ভিন্ন প্রকারে রূপান্তর করতে হবে। ডেটা স্ট্রিম রূপান্তরের জন্য আরেকটি সাধারণ ব্যবহারের ক্ষেত্রে তালিকা বিভাজক যোগ করা হচ্ছে

আরও সাধারণভাবে, ডেটা স্ট্রীমে সরাসরি রূপান্তর প্রয়োগ করা আপনাকে আপনার সংগ্রহস্থলের গঠন এবং UI গঠনগুলিকে আলাদা রাখতে দেয়।

এই পৃষ্ঠাটি অনুমান করে যে আপনি পেজিং লাইব্রেরির মৌলিক ব্যবহারের সাথে পরিচিত।

মৌলিক রূপান্তর প্রয়োগ করুন

যেহেতু PagingData একটি প্রতিক্রিয়াশীল স্ট্রীমে এনক্যাপসুলেট করা হয়েছে, আপনি ডেটা লোড করা এবং উপস্থাপন করার মধ্যে ক্রমবর্ধমানভাবে ডেটাতে রূপান্তর ক্রিয়াকলাপ প্রয়োগ করতে পারেন।

স্ট্রীমের প্রতিটি PagingData অবজেক্টে রূপান্তর প্রয়োগ করার জন্য, স্ট্রীমে একটি map() অপারেশনের ভিতরে রূপান্তরগুলি রাখুন:

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  // Map the outer stream so that the transformations are applied to
  // each new generation of PagingData.
  .map { pagingData ->
    // Transformations in this block are applied to the items
    // in the paged data.
}

জাভা

PagingRx.getFlowable(pager) // Type is Flowable<PagingData<User>>.
  // Map the outer stream so that the transformations are applied to
  // each new generation of PagingData.
  .map(pagingData -> {
    // Transformations in this block are applied to the items
    // in the paged data.
  });

জাভা

// Map the outer stream so that the transformations are applied to
// each new generation of PagingData.
Transformations.map(
  // Type is LiveData<PagingData<User>>.
  PagingLiveData.getLiveData(pager),
  pagingData -> {
    // Transformations in this block are applied to the items
    // in the paged data.
  });

ডেটা রূপান্তর করুন

ডেটার একটি প্রবাহের সবচেয়ে মৌলিক ক্রিয়াকলাপ হল এটিকে একটি ভিন্ন ধরনের রূপান্তর করা। একবার আপনি PagingData অবজেক্টে অ্যাক্সেস পেয়ে গেলে, আপনি PagingData অবজেক্টের মধ্যে পৃষ্ঠা তালিকার প্রতিটি পৃথক আইটেমের উপর একটি map() অপারেশন করতে পারেন।

এটির জন্য একটি সাধারণ ব্যবহারের ক্ষেত্রে একটি নেটওয়ার্ক বা ডাটাবেস স্তর অবজেক্টকে নির্দিষ্টভাবে UI স্তরে ব্যবহৃত বস্তুর উপর ম্যাপ করা। নীচের উদাহরণটি দেখায় কিভাবে এই ধরনের মানচিত্র অপারেশন প্রয়োগ করতে হয়:

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  .map { pagingData ->
    pagingData.map { user -> UiModel(user) }
  }

জাভা

// Type is Flowable<PagingData<User>>.
PagingRx.getFlowable(pager)
  .map(pagingData ->
    pagingData.map(UiModel.UserModel::new)
  )

জাভা

Transformations.map(
  // Type is LiveData<PagingData<User>>.
  PagingLiveData.getLiveData(pager),
  pagingData ->
    pagingData.map(UiModel.UserModel::new)
)

আরেকটি সাধারণ ডেটা রূপান্তর হল ব্যবহারকারীর কাছ থেকে একটি ইনপুট নেওয়া, যেমন একটি ক্যোয়ারী স্ট্রিং, এবং এটিকে প্রদর্শনের জন্য অনুরোধ আউটপুটে রূপান্তর করা। এটি সেট আপ করার জন্য ব্যবহারকারীর ক্যোয়ারী ইনপুট শোনা এবং ক্যাপচার করা, অনুরোধটি সম্পাদন করা এবং ক্যোয়ারী ফলাফলটিকে UI-তে পুশ করা প্রয়োজন৷

আপনি একটি স্ট্রিম API ব্যবহার করে ক্যোয়ারী ইনপুট শুনতে পারেন। আপনার ViewModel এ স্ট্রিম রেফারেন্স রাখুন। UI স্তরের এটিতে সরাসরি অ্যাক্সেস থাকা উচিত নয়; পরিবর্তে, ব্যবহারকারীর প্রশ্নের ভিউমডেলকে অবহিত করার জন্য একটি ফাংশন সংজ্ঞায়িত করুন।

কোটলিন

private val queryFlow = MutableStateFlow("")

fun onQueryChanged(query: String) {
  queryFlow.value = query
}

জাভা

private BehaviorSubject<String> querySubject = BehaviorSubject.create("");

public void onQueryChanged(String query) {
  queryFlow.onNext(query)
}

জাভা

private MutableLiveData<String> queryLiveData = new MutableLiveData("");

public void onQueryChanged(String query) {
  queryFlow.setValue(query)
}

যখন ডেটা স্ট্রীমে ক্যোয়ারী মান পরিবর্তিত হয়, আপনি ক্যোয়ারী মানটিকে পছন্দসই ডেটা টাইপে রূপান্তর করতে এবং ফলাফলটি UI স্তরে ফিরিয়ে দিতে অপারেশন করতে পারেন। নির্দিষ্ট রূপান্তর ফাংশন ব্যবহৃত ভাষা এবং কাঠামোর উপর নির্ভর করে, কিন্তু তারা সব একই কার্যকারিতা প্রদান করে।

কোটলিন

val querySearchResults = queryFlow.flatMapLatest { query ->
  // The database query returns a Flow which is output through
  // querySearchResults
  userDatabase.searchBy(query)
}

জাভা

Observable<User> querySearchResults =
  querySubject.switchMap(query -> userDatabase.searchBy(query));

জাভা

LiveData<User> querySearchResults = Transformations.switchMap(
  queryLiveData,
  query -> userDatabase.searchBy(query)
);

flatMapLatest বা switchMap মতো ক্রিয়াকলাপগুলি ব্যবহার করা নিশ্চিত করে যে কেবলমাত্র সর্বশেষ ফলাফলগুলিই UI-তে ফিরে আসবে৷ যদি ব্যবহারকারী ডাটাবেস অপারেশন সম্পূর্ণ হওয়ার আগে তাদের ক্যোয়ারী ইনপুট পরিবর্তন করে, এই অপারেশনগুলি পুরানো ক্যোয়ারী থেকে ফলাফল বাতিল করে এবং অবিলম্বে নতুন অনুসন্ধান চালু করে।

ফিল্টার ডেটা

আরেকটি সাধারণ অপারেশন হল ফিল্টারিং। আপনি ব্যবহারকারীর মানদণ্ডের উপর ভিত্তি করে ডেটা ফিল্টার করতে পারেন, অথবা আপনি UI থেকে ডেটা সরাতে পারেন যদি এটি অন্য মানদণ্ডের উপর ভিত্তি করে লুকানো উচিত।

আপনাকে এই ফিল্টার অপারেশনগুলি map() কলের ভিতরে রাখতে হবে কারণ ফিল্টারটি PagingData অবজেক্টে প্রযোজ্য। একবার PagingData থেকে ডেটা ফিল্টার করা হয়ে গেলে, নতুন PagingData ইনস্ট্যান্স প্রদর্শনের জন্য UI স্তরে পাস করা হয়।

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  .map { pagingData ->
    pagingData.filter { user -> !user.hiddenFromUi }
  }

জাভা

// Type is Flowable<PagingData<User>>.
PagingRx.getFlowable(pager)
  .map(pagingData ->
    pagingData.filter(user -> !user.isHiddenFromUi())
  )
}

জাভা

Transformations.map(
  // Type is LiveData<PagingData<User>>.
  PagingLiveData.getLiveData(pager),
  pagingData ->
    pagingData.filter(user -> !user.isHiddenFromUi())
)

তালিকা বিভাজক যোগ করুন

পেজিং লাইব্রেরি গতিশীল তালিকা বিভাজক সমর্থন করে। আপনি RecyclerView তালিকা আইটেম হিসাবে ডেটা স্ট্রীমে সরাসরি বিভাজক সন্নিবেশ করে তালিকা পাঠযোগ্যতা উন্নত করতে পারেন। ফলস্বরূপ, বিভাজকগুলি সম্পূর্ণরূপে বৈশিষ্ট্যযুক্ত ViewHolder অবজেক্ট, ইন্টারঅ্যাক্টিভিটি, অ্যাক্সেসিবিলিটি ফোকাস এবং একটি View দ্বারা প্রদত্ত অন্যান্য সমস্ত বৈশিষ্ট্য সক্ষম করে।

আপনার পৃষ্ঠা তালিকায় বিভাজক সন্নিবেশ করার জন্য তিনটি ধাপ জড়িত:

  1. বিভাজক আইটেম মিটমাট করতে UI মডেল রূপান্তর করুন.
  2. ডেটা লোড করা এবং ডেটা উপস্থাপনের মধ্যে গতিশীলভাবে বিভাজক যুক্ত করতে ডেটা স্ট্রিমকে রূপান্তর করুন।
  3. বিভাজক আইটেমগুলি পরিচালনা করতে UI আপডেট করুন।

UI মডেলটি রূপান্তর করুন

পেজিং লাইব্রেরি প্রকৃত তালিকা আইটেম হিসাবে RecyclerView এ তালিকা বিভাজক সন্নিবেশ করায়, কিন্তু বিভাজক আইটেমগুলিকে তালিকার ডেটা আইটেমগুলি থেকে আলাদা করতে হবে যাতে একটি পৃথক UI সহ একটি ভিন্ন ViewHolder প্রকারের সাথে আবদ্ধ হতে সক্ষম হয়৷ সমাধান হল আপনার ডেটা এবং আপনার বিভাজকদের প্রতিনিধিত্ব করার জন্য সাবক্লাস সহ একটি কোটলিন সিল করা ক্লাস তৈরি করা। বিকল্পভাবে, আপনি একটি বেস ক্লাস তৈরি করতে পারেন যা আপনার তালিকা আইটেম ক্লাস এবং আপনার বিভাজক শ্রেণী দ্বারা প্রসারিত হয়।

ধরুন আপনি User আইটেমগুলির একটি পৃষ্ঠাযুক্ত তালিকায় বিভাজক যোগ করতে চান। নিম্নলিখিত স্নিপেট দেখায় কিভাবে একটি বেস ক্লাস তৈরি করতে হয় যেখানে উদাহরণগুলি হয় একটি UserModel বা একটি SeparatorModel হতে পারে:

কোটলিন

sealed class UiModel {
  class UserModel(val id: String, val label: String) : UiModel() {
    constructor(user: User) : this(user.id, user.label)
  }

  class SeparatorModel(val description: String) : UiModel()
}

জাভা

class UiModel {
  private UiModel() {}

  static class UserModel extends UiModel {
    @NonNull
    private String mId;
    @NonNull
    private String mLabel;

    UserModel(@NonNull String id, @NonNull String label) {
      mId = id;
      mLabel = label;
    }

    UserModel(@NonNull User user) {
      mId = user.id;
      mLabel = user.label;
    }

    @NonNull
    public String getId() {
      return mId;
    }

    @NonNull
    public String getLabel() {
      return mLabel;
      }
    }

    static class SeparatorModel extends UiModel {
    @NonNull
    private String mDescription;

    SeparatorModel(@NonNull String description) {
      mDescription = description;
    }

    @NonNull
    public String getDescription() {
      return mDescription;
    }
  }
}

জাভা

class UiModel {
  private UiModel() {}

  static class UserModel extends UiModel {
    @NonNull
    private String mId;
    @NonNull
    private String mLabel;

    UserModel(@NonNull String id, @NonNull String label) {
      mId = id;
      mLabel = label;
    }

    UserModel(@NonNull User user) {
      mId = user.id;
      mLabel = user.label;
    }

    @NonNull
    public String getId() {
      return mId;
    }

    @NonNull
    public String getLabel() {
      return mLabel;
      }
    }

    static class SeparatorModel extends UiModel {
    @NonNull
    private String mDescription;

    SeparatorModel(@NonNull String description) {
      mDescription = description;
    }

    @NonNull
    public String getDescription() {
      return mDescription;
    }
  }
}

ডেটা স্ট্রিম রূপান্তর করুন

এটি লোড করার পরে এবং আপনি এটি উপস্থাপন করার আগে আপনাকে অবশ্যই ডেটা স্ট্রীমে রূপান্তর প্রয়োগ করতে হবে। রূপান্তরগুলি নিম্নলিখিতগুলি করা উচিত:

  • নতুন বেস আইটেম টাইপ প্রতিফলিত করতে লোড করা তালিকা আইটেম রূপান্তর করুন.
  • বিভাজক যোগ করতে PagingData.insertSeparators() পদ্ধতি ব্যবহার করুন।

রূপান্তর ক্রিয়াকলাপ সম্পর্কে আরও জানতে, মৌলিক রূপান্তর প্রয়োগ করুন দেখুন।

নিম্নলিখিত উদাহরণে PagingData<User> স্ট্রীমকে একটি PagingData<UiModel> স্ট্রীমে বিভাজক যোগ করার জন্য আপডেট করার জন্য রূপান্তর অপারেশন দেখায়:

কোটলিন

pager.flow.map { pagingData: PagingData<User> ->
  // Map outer stream, so you can perform transformations on
  // each paging generation.
  pagingData
  .map { user ->
    // Convert items in stream to UiModel.UserModel.
    UiModel.UserModel(user)
  }
  .insertSeparators<UiModel.UserModel, UiModel> { before, after ->
    when {
      before == null -> UiModel.SeparatorModel("HEADER")
      after == null -> UiModel.SeparatorModel("FOOTER")
      shouldSeparate(before, after) -> UiModel.SeparatorModel(
        "BETWEEN ITEMS $before AND $after"
      )
      // Return null to avoid adding a separator between two items.
      else -> null
    }
  }
}

জাভা

// Map outer stream, so you can perform transformations on each
// paging generation.
PagingRx.getFlowable(pager).map(pagingData -> {
  // First convert items in stream to UiModel.UserModel.
  PagingData<UiModel> uiModelPagingData = pagingData.map(
    UiModel.UserModel::new);

  // Insert UiModel.SeparatorModel, which produces PagingData of
  // generic type UiModel.
  return PagingData.insertSeparators(uiModelPagingData,
    (@Nullable UiModel before, @Nullable UiModel after) -> {
      if (before == null) {
        return new UiModel.SeparatorModel("HEADER");
      } else if (after == null) {
        return new UiModel.SeparatorModel("FOOTER");
      } else if (shouldSeparate(before, after)) {
        return new UiModel.SeparatorModel("BETWEEN ITEMS "
          + before.toString() + " AND " + after.toString());
      } else {
        // Return null to avoid adding a separator between two
        // items.
        return null;
      }
    });
});

জাভা

// Map outer stream, so you can perform transformations on each
// paging generation.
Transformations.map(PagingLiveData.getLiveData(pager),
  pagingData -> {
    // First convert items in stream to UiModel.UserModel.
    PagingData<UiModel> uiModelPagingData = pagingData.map(
      UiModel.UserModel::new);

    // Insert UiModel.SeparatorModel, which produces PagingData of
    // generic type UiModel.
    return PagingData.insertSeparators(uiModelPagingData,
      (@Nullable UiModel before, @Nullable UiModel after) -> {
        if (before == null) {
          return new UiModel.SeparatorModel("HEADER");
        } else if (after == null) {
          return new UiModel.SeparatorModel("FOOTER");
        } else if (shouldSeparate(before, after)) {
          return new UiModel.SeparatorModel("BETWEEN ITEMS "
            + before.toString() + " AND " + after.toString());
        } else {
          // Return null to avoid adding a separator between two
          // items.
          return null;
        }
      });
  });

UI এ বিভাজক হ্যান্ডেল করুন

বিভাজক আইটেম টাইপ মিটমাট করার জন্য আপনার UI পরিবর্তন করা চূড়ান্ত পদক্ষেপ। আপনার বিভাজক আইটেমগুলির জন্য একটি লেআউট এবং একটি ভিউ হোল্ডার তৈরি করুন এবং RecyclerView.ViewHolder এর ভিউ হোল্ডার টাইপ হিসাবে ব্যবহার করতে তালিকা অ্যাডাপ্টারটি পরিবর্তন করুন যাতে এটি একাধিক ধরণের ভিউ হোল্ডার পরিচালনা করতে পারে। বিকল্পভাবে, আপনি একটি সাধারণ বেস ক্লাস সংজ্ঞায়িত করতে পারেন যা আপনার আইটেম এবং বিভাজক ভিউ হোল্ডার ক্লাস উভয়ই প্রসারিত করে।

এছাড়াও আপনাকে আপনার তালিকা অ্যাডাপ্টারে নিম্নলিখিত পরিবর্তনগুলি করতে হবে:

  • বিভাজক তালিকা আইটেমগুলির জন্য অ্যাকাউন্টের জন্য onCreateViewHolder() এবং onBindViewHolder() পদ্ধতিতে কেস যোগ করুন।
  • একটি নতুন তুলনামূলক প্রয়োগ করুন।

কোটলিন

class UiModelAdapter :
  PagingDataAdapter<UiModel, RecyclerView.ViewHolder>(UiModelComparator) {

  override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int
  ) = when (viewType) {
    R.layout.item -> UserModelViewHolder(parent)
    else -> SeparatorModelViewHolder(parent)
  }

  override fun getItemViewType(position: Int) {
    // Use peek over getItem to avoid triggering page fetch / drops, since
    // recycling views is not indicative of the user's current scroll position.
    return when (peek(position)) {
      is UiModel.UserModel -> R.layout.item
      is UiModel.SeparatorModel -> R.layout.separator_item
      null -> throw IllegalStateException("Unknown view")
    }
  }

  override fun onBindViewHolder(
    holder: RecyclerView.ViewHolder,
    position: Int
  ) {
    val item = getItem(position)
    if (holder is UserModelViewHolder) {
      holder.bind(item as UserModel)
    } else if (holder is SeparatorModelViewHolder) {
      holder.bind(item as SeparatorModel)
    }
  }
}

object UiModelComparator : DiffUtil.ItemCallback<UiModel>() {
  override fun areItemsTheSame(
    oldItem: UiModel,
    newItem: UiModel
  ): Boolean {
    val isSameRepoItem = oldItem is UiModel.UserModel
      && newItem is UiModel.UserModel
      && oldItem.id == newItem.id

    val isSameSeparatorItem = oldItem is UiModel.SeparatorModel
      && newItem is UiModel.SeparatorModel
      && oldItem.description == newItem.description

    return isSameRepoItem || isSameSeparatorItem
  }

  override fun areContentsTheSame(
    oldItem: UiModel,
    newItem: UiModel
  ) = oldItem == newItem
}

জাভা

class UiModelAdapter extends PagingDataAdapter<UiModel, RecyclerView.ViewHolder> {
  UiModelAdapter() {
    super(new UiModelComparator(), Dispatchers.getMain(),
      Dispatchers.getDefault());
  }

  @NonNull
  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
    int viewType) {
    if (viewType == R.layout.item) {
      return new UserModelViewHolder(parent);
    } else {
      return new SeparatorModelViewHolder(parent);
    }
  }

  @Override
  public int getItemViewType(int position) {
    // Use peek over getItem to avoid triggering page fetch / drops, since
    // recycling views is not indicative of the user's current scroll position.
    UiModel item = peek(position);
    if (item instanceof UiModel.UserModel) {
      return R.layout.item;
    } else if (item instanceof UiModel.SeparatorModel) {
      return R.layout.separator_item;
    } else {
      throw new IllegalStateException("Unknown view");
    }
  }

  @Override
  public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,
    int position) {
    if (holder instanceOf UserModelViewHolder) {
      UserModel userModel = (UserModel) getItem(position);
      ((UserModelViewHolder) holder).bind(userModel);
    } else {
      SeparatorModel separatorModel = (SeparatorModel) getItem(position);
      ((SeparatorModelViewHolder) holder).bind(separatorModel);
    }
  }
}

class UiModelComparator extends DiffUtil.ItemCallback<UiModel> {
  @Override
  public boolean areItemsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    boolean isSameRepoItem = oldItem instanceof UserModel
      && newItem instanceof UserModel
      && ((UserModel) oldItem).getId().equals(((UserModel) newItem).getId());

    boolean isSameSeparatorItem = oldItem instanceof SeparatorModel
      && newItem instanceof SeparatorModel
      && ((SeparatorModel) oldItem).getDescription().equals(
      ((SeparatorModel) newItem).getDescription());

    return isSameRepoItem || isSameSeparatorItem;
  }

  @Override
  public boolean areContentsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    return oldItem.equals(newItem);
  }
}

জাভা

class UiModelAdapter extends PagingDataAdapter<UiModel, RecyclerView.ViewHolder> {
  UiModelAdapter() {
    super(new UiModelComparator(), Dispatchers.getMain(),
      Dispatchers.getDefault());
  }

  @NonNull
  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
    int viewType) {
    if (viewType == R.layout.item) {
      return new UserModelViewHolder(parent);
    } else {
      return new SeparatorModelViewHolder(parent);
    }
  }

  @Override
  public int getItemViewType(int position) {
    // Use peek over getItem to avoid triggering page fetch / drops, since
    // recycling views is not indicative of the user's current scroll position.
    UiModel item = peek(position);
    if (item instanceof UiModel.UserModel) {
      return R.layout.item;
    } else if (item instanceof UiModel.SeparatorModel) {
      return R.layout.separator_item;
    } else {
      throw new IllegalStateException("Unknown view");
    }
  }

  @Override
  public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,
    int position) {
    if (holder instanceOf UserModelViewHolder) {
      UserModel userModel = (UserModel) getItem(position);
      ((UserModelViewHolder) holder).bind(userModel);
    } else {
      SeparatorModel separatorModel = (SeparatorModel) getItem(position);
      ((SeparatorModelViewHolder) holder).bind(separatorModel);
    }
  }
}

class UiModelComparator extends DiffUtil.ItemCallback<UiModel> {
  @Override
  public boolean areItemsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    boolean isSameRepoItem = oldItem instanceof UserModel
      && newItem instanceof UserModel
      && ((UserModel) oldItem).getId().equals(((UserModel) newItem).getId());

    boolean isSameSeparatorItem = oldItem instanceof SeparatorModel
      && newItem instanceof SeparatorModel
      && ((SeparatorModel) oldItem).getDescription().equals(
      ((SeparatorModel) newItem).getDescription());

    return isSameRepoItem || isSameSeparatorItem;
  }

  @Override
  public boolean areContentsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    return oldItem.equals(newItem);
  }
}

নকল কাজ এড়িয়ে চলুন

এড়ানোর জন্য একটি মূল সমস্যা হল অ্যাপটিকে অপ্রয়োজনীয় কাজ করা। ডেটা আনা একটি ব্যয়বহুল অপারেশন, এবং ডেটা রূপান্তরও মূল্যবান সময় নিতে পারে। একবার ডেটা লোড হয়ে গেলে এবং UI-তে প্রদর্শনের জন্য প্রস্তুত হয়ে গেলে, কনফিগারেশন পরিবর্তনের ক্ষেত্রে এবং UI পুনরায় তৈরি করার প্রয়োজন হলে এটি সংরক্ষণ করা উচিত।

cachedIn() অপারেশন এর আগে ঘটে যাওয়া যেকোনো রূপান্তরের ফলাফল ক্যাশে করে। অতএব, cachedIn() আপনার ভিউমডেলের শেষ কল হওয়া উচিত।

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  .map { pagingData ->
    pagingData.filter { user -> !user.hiddenFromUi }
      .map { user -> UiModel.UserModel(user) }
  }
  .cachedIn(viewModelScope)

জাভা

// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
PagingRx.cachedIn(
  // Type is Flowable<PagingData<User>>.
  PagingRx.getFlowable(pager)
    .map(pagingData -> pagingData
      .filter(user -> !user.isHiddenFromUi())
      .map(UiModel.UserModel::new)),
  viewModelScope);
}

জাভা

// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
PagingLiveData.cachedIn(
  Transformations.map(
    // Type is LiveData<PagingData<User>>.
    PagingLiveData.getLiveData(pager),
    pagingData -> pagingData
      .filter(user -> !user.isHiddenFromUi())
      .map(UiModel.UserModel::new)),
  viewModelScope);

PagingData এর একটি স্ট্রিমের সাথে cachedIn() ব্যবহার করার বিষয়ে আরও তথ্যের জন্য, পেজিং ডেটার একটি স্ট্রিম সেট আপ করুন দেখুন।

অতিরিক্ত সম্পদ

পেজিং লাইব্রেরি সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত সংস্থানগুলি দেখুন:

কোডল্যাব

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %} ,

আপনি যখন পৃষ্ঠাযুক্ত ডেটা নিয়ে কাজ করেন , তখন আপনাকে প্রায়ই ডেটা স্ট্রীমটি লোড করার সাথে সাথে রূপান্তর করতে হবে। উদাহরণস্বরূপ, আপনাকে আইটেমগুলির একটি তালিকা ফিল্টার করতে হতে পারে, বা আইটেমগুলিকে UI-তে উপস্থাপন করার আগে একটি ভিন্ন প্রকারে রূপান্তর করতে হবে। ডেটা স্ট্রিম রূপান্তরের জন্য আরেকটি সাধারণ ব্যবহারের ক্ষেত্রে তালিকা বিভাজক যোগ করা হচ্ছে

আরও সাধারণভাবে, ডেটা স্ট্রীমে সরাসরি রূপান্তর প্রয়োগ করা আপনাকে আপনার সংগ্রহস্থলের গঠন এবং UI গঠনগুলিকে আলাদা রাখতে দেয়।

এই পৃষ্ঠাটি অনুমান করে যে আপনি পেজিং লাইব্রেরির মৌলিক ব্যবহারের সাথে পরিচিত।

মৌলিক রূপান্তর প্রয়োগ করুন

যেহেতু PagingData একটি প্রতিক্রিয়াশীল স্ট্রীমে এনক্যাপসুলেট করা হয়েছে, আপনি ডেটা লোড করা এবং উপস্থাপন করার মধ্যে ক্রমবর্ধমানভাবে ডেটাতে রূপান্তর ক্রিয়াকলাপ প্রয়োগ করতে পারেন।

স্ট্রীমের প্রতিটি PagingData অবজেক্টে রূপান্তর প্রয়োগ করার জন্য, স্ট্রীমে একটি map() অপারেশনের ভিতরে রূপান্তরগুলি রাখুন:

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  // Map the outer stream so that the transformations are applied to
  // each new generation of PagingData.
  .map { pagingData ->
    // Transformations in this block are applied to the items
    // in the paged data.
}

জাভা

PagingRx.getFlowable(pager) // Type is Flowable<PagingData<User>>.
  // Map the outer stream so that the transformations are applied to
  // each new generation of PagingData.
  .map(pagingData -> {
    // Transformations in this block are applied to the items
    // in the paged data.
  });

জাভা

// Map the outer stream so that the transformations are applied to
// each new generation of PagingData.
Transformations.map(
  // Type is LiveData<PagingData<User>>.
  PagingLiveData.getLiveData(pager),
  pagingData -> {
    // Transformations in this block are applied to the items
    // in the paged data.
  });

ডেটা রূপান্তর করুন

ডেটার একটি প্রবাহের সবচেয়ে মৌলিক ক্রিয়াকলাপ হল এটিকে একটি ভিন্ন ধরনের রূপান্তর করা। একবার আপনি PagingData অবজেক্টে অ্যাক্সেস পেয়ে গেলে, আপনি PagingData অবজেক্টের মধ্যে পৃষ্ঠা তালিকার প্রতিটি পৃথক আইটেমের উপর একটি map() অপারেশন করতে পারেন।

এটির জন্য একটি সাধারণ ব্যবহারের ক্ষেত্রে একটি নেটওয়ার্ক বা ডাটাবেস স্তর অবজেক্টকে নির্দিষ্টভাবে UI স্তরে ব্যবহৃত বস্তুর উপর ম্যাপ করা। নীচের উদাহরণটি দেখায় কিভাবে এই ধরনের মানচিত্র অপারেশন প্রয়োগ করতে হয়:

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  .map { pagingData ->
    pagingData.map { user -> UiModel(user) }
  }

জাভা

// Type is Flowable<PagingData<User>>.
PagingRx.getFlowable(pager)
  .map(pagingData ->
    pagingData.map(UiModel.UserModel::new)
  )

জাভা

Transformations.map(
  // Type is LiveData<PagingData<User>>.
  PagingLiveData.getLiveData(pager),
  pagingData ->
    pagingData.map(UiModel.UserModel::new)
)

আরেকটি সাধারণ ডেটা রূপান্তর হল ব্যবহারকারীর কাছ থেকে একটি ইনপুট নেওয়া, যেমন একটি ক্যোয়ারী স্ট্রিং, এবং এটিকে প্রদর্শনের জন্য অনুরোধ আউটপুটে রূপান্তর করা। এটি সেট আপ করার জন্য ব্যবহারকারীর ক্যোয়ারী ইনপুট শোনা এবং ক্যাপচার করা, অনুরোধটি সম্পাদন করা এবং ক্যোয়ারী ফলাফলটিকে UI-তে পুশ করা প্রয়োজন৷

আপনি একটি স্ট্রিম API ব্যবহার করে ক্যোয়ারী ইনপুট শুনতে পারেন। আপনার ViewModel এ স্ট্রিম রেফারেন্স রাখুন। UI স্তরের এটিতে সরাসরি অ্যাক্সেস থাকা উচিত নয়; পরিবর্তে, ব্যবহারকারীর প্রশ্নের ভিউমডেলকে অবহিত করার জন্য একটি ফাংশন সংজ্ঞায়িত করুন।

কোটলিন

private val queryFlow = MutableStateFlow("")

fun onQueryChanged(query: String) {
  queryFlow.value = query
}

জাভা

private BehaviorSubject<String> querySubject = BehaviorSubject.create("");

public void onQueryChanged(String query) {
  queryFlow.onNext(query)
}

জাভা

private MutableLiveData<String> queryLiveData = new MutableLiveData("");

public void onQueryChanged(String query) {
  queryFlow.setValue(query)
}

যখন ডেটা স্ট্রীমে ক্যোয়ারী মান পরিবর্তিত হয়, আপনি ক্যোয়ারী মানটিকে পছন্দসই ডেটা টাইপে রূপান্তর করতে এবং ফলাফলটি UI স্তরে ফিরিয়ে দিতে অপারেশন করতে পারেন। নির্দিষ্ট রূপান্তর ফাংশন ব্যবহৃত ভাষা এবং কাঠামোর উপর নির্ভর করে, কিন্তু তারা সব একই কার্যকারিতা প্রদান করে।

কোটলিন

val querySearchResults = queryFlow.flatMapLatest { query ->
  // The database query returns a Flow which is output through
  // querySearchResults
  userDatabase.searchBy(query)
}

জাভা

Observable<User> querySearchResults =
  querySubject.switchMap(query -> userDatabase.searchBy(query));

জাভা

LiveData<User> querySearchResults = Transformations.switchMap(
  queryLiveData,
  query -> userDatabase.searchBy(query)
);

flatMapLatest বা switchMap মতো ক্রিয়াকলাপগুলি ব্যবহার করা নিশ্চিত করে যে কেবলমাত্র সর্বশেষ ফলাফলগুলিই UI-তে ফিরে আসবে৷ যদি ব্যবহারকারী ডাটাবেস অপারেশন সম্পূর্ণ হওয়ার আগে তাদের ক্যোয়ারী ইনপুট পরিবর্তন করে, এই অপারেশনগুলি পুরানো ক্যোয়ারী থেকে ফলাফল বাতিল করে এবং অবিলম্বে নতুন অনুসন্ধান চালু করে।

ফিল্টার ডেটা

আরেকটি সাধারণ অপারেশন হল ফিল্টারিং। আপনি ব্যবহারকারীর মানদণ্ডের উপর ভিত্তি করে ডেটা ফিল্টার করতে পারেন, অথবা আপনি UI থেকে ডেটা সরাতে পারেন যদি এটি অন্য মানদণ্ডের উপর ভিত্তি করে লুকানো উচিত।

আপনাকে এই ফিল্টার অপারেশনগুলি map() কলের ভিতরে রাখতে হবে কারণ ফিল্টারটি PagingData অবজেক্টে প্রযোজ্য। একবার PagingData থেকে ডেটা ফিল্টার করা হয়ে গেলে, নতুন PagingData ইনস্ট্যান্স প্রদর্শনের জন্য UI স্তরে পাস করা হয়।

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  .map { pagingData ->
    pagingData.filter { user -> !user.hiddenFromUi }
  }

জাভা

// Type is Flowable<PagingData<User>>.
PagingRx.getFlowable(pager)
  .map(pagingData ->
    pagingData.filter(user -> !user.isHiddenFromUi())
  )
}

জাভা

Transformations.map(
  // Type is LiveData<PagingData<User>>.
  PagingLiveData.getLiveData(pager),
  pagingData ->
    pagingData.filter(user -> !user.isHiddenFromUi())
)

তালিকা বিভাজক যোগ করুন

পেজিং লাইব্রেরি গতিশীল তালিকা বিভাজক সমর্থন করে। আপনি RecyclerView তালিকা আইটেম হিসাবে ডেটা স্ট্রীমে সরাসরি বিভাজক সন্নিবেশ করে তালিকা পাঠযোগ্যতা উন্নত করতে পারেন। ফলস্বরূপ, বিভাজকগুলি সম্পূর্ণরূপে বৈশিষ্ট্যযুক্ত ViewHolder অবজেক্ট, ইন্টারঅ্যাক্টিভিটি, অ্যাক্সেসিবিলিটি ফোকাস এবং একটি View দ্বারা প্রদত্ত অন্যান্য সমস্ত বৈশিষ্ট্য সক্ষম করে।

আপনার পৃষ্ঠা তালিকায় বিভাজক সন্নিবেশ করার জন্য তিনটি ধাপ জড়িত:

  1. বিভাজক আইটেম মিটমাট করতে UI মডেল রূপান্তর করুন.
  2. ডেটা লোড করা এবং ডেটা উপস্থাপনের মধ্যে গতিশীলভাবে বিভাজক যুক্ত করতে ডেটা স্ট্রিমকে রূপান্তর করুন।
  3. বিভাজক আইটেমগুলি পরিচালনা করতে UI আপডেট করুন।

UI মডেলটি রূপান্তর করুন

পেজিং লাইব্রেরি প্রকৃত তালিকা আইটেম হিসাবে RecyclerView এ তালিকা বিভাজক সন্নিবেশ করায়, কিন্তু বিভাজক আইটেমগুলিকে তালিকার ডেটা আইটেমগুলি থেকে আলাদা করতে হবে যাতে একটি পৃথক UI সহ একটি ভিন্ন ViewHolder প্রকারের সাথে আবদ্ধ হতে সক্ষম হয়৷ সমাধান হল আপনার ডেটা এবং আপনার বিভাজকদের প্রতিনিধিত্ব করার জন্য সাবক্লাস সহ একটি কোটলিন সিল করা ক্লাস তৈরি করা। বিকল্পভাবে, আপনি একটি বেস ক্লাস তৈরি করতে পারেন যা আপনার তালিকা আইটেম ক্লাস এবং আপনার বিভাজক শ্রেণী দ্বারা প্রসারিত হয়।

ধরুন আপনি User আইটেমগুলির একটি পৃষ্ঠাযুক্ত তালিকায় বিভাজক যোগ করতে চান। নিম্নলিখিত স্নিপেট দেখায় কিভাবে একটি বেস ক্লাস তৈরি করতে হয় যেখানে উদাহরণগুলি হয় একটি UserModel বা একটি SeparatorModel হতে পারে:

কোটলিন

sealed class UiModel {
  class UserModel(val id: String, val label: String) : UiModel() {
    constructor(user: User) : this(user.id, user.label)
  }

  class SeparatorModel(val description: String) : UiModel()
}

জাভা

class UiModel {
  private UiModel() {}

  static class UserModel extends UiModel {
    @NonNull
    private String mId;
    @NonNull
    private String mLabel;

    UserModel(@NonNull String id, @NonNull String label) {
      mId = id;
      mLabel = label;
    }

    UserModel(@NonNull User user) {
      mId = user.id;
      mLabel = user.label;
    }

    @NonNull
    public String getId() {
      return mId;
    }

    @NonNull
    public String getLabel() {
      return mLabel;
      }
    }

    static class SeparatorModel extends UiModel {
    @NonNull
    private String mDescription;

    SeparatorModel(@NonNull String description) {
      mDescription = description;
    }

    @NonNull
    public String getDescription() {
      return mDescription;
    }
  }
}

জাভা

class UiModel {
  private UiModel() {}

  static class UserModel extends UiModel {
    @NonNull
    private String mId;
    @NonNull
    private String mLabel;

    UserModel(@NonNull String id, @NonNull String label) {
      mId = id;
      mLabel = label;
    }

    UserModel(@NonNull User user) {
      mId = user.id;
      mLabel = user.label;
    }

    @NonNull
    public String getId() {
      return mId;
    }

    @NonNull
    public String getLabel() {
      return mLabel;
      }
    }

    static class SeparatorModel extends UiModel {
    @NonNull
    private String mDescription;

    SeparatorModel(@NonNull String description) {
      mDescription = description;
    }

    @NonNull
    public String getDescription() {
      return mDescription;
    }
  }
}

ডেটা স্ট্রিম রূপান্তর করুন

এটি লোড করার পরে এবং আপনি এটি উপস্থাপন করার আগে আপনাকে অবশ্যই ডেটা স্ট্রীমে রূপান্তর প্রয়োগ করতে হবে। রূপান্তরগুলি নিম্নলিখিতগুলি করা উচিত:

  • নতুন বেস আইটেম টাইপ প্রতিফলিত করতে লোড করা তালিকা আইটেম রূপান্তর করুন.
  • বিভাজক যোগ করতে PagingData.insertSeparators() পদ্ধতি ব্যবহার করুন।

রূপান্তর ক্রিয়াকলাপ সম্পর্কে আরও জানতে, মৌলিক রূপান্তর প্রয়োগ করুন দেখুন।

নিম্নলিখিত উদাহরণে PagingData<User> স্ট্রীমকে একটি PagingData<UiModel> স্ট্রীমে বিভাজক যোগ করার জন্য আপডেট করার জন্য রূপান্তর অপারেশন দেখায়:

কোটলিন

pager.flow.map { pagingData: PagingData<User> ->
  // Map outer stream, so you can perform transformations on
  // each paging generation.
  pagingData
  .map { user ->
    // Convert items in stream to UiModel.UserModel.
    UiModel.UserModel(user)
  }
  .insertSeparators<UiModel.UserModel, UiModel> { before, after ->
    when {
      before == null -> UiModel.SeparatorModel("HEADER")
      after == null -> UiModel.SeparatorModel("FOOTER")
      shouldSeparate(before, after) -> UiModel.SeparatorModel(
        "BETWEEN ITEMS $before AND $after"
      )
      // Return null to avoid adding a separator between two items.
      else -> null
    }
  }
}

জাভা

// Map outer stream, so you can perform transformations on each
// paging generation.
PagingRx.getFlowable(pager).map(pagingData -> {
  // First convert items in stream to UiModel.UserModel.
  PagingData<UiModel> uiModelPagingData = pagingData.map(
    UiModel.UserModel::new);

  // Insert UiModel.SeparatorModel, which produces PagingData of
  // generic type UiModel.
  return PagingData.insertSeparators(uiModelPagingData,
    (@Nullable UiModel before, @Nullable UiModel after) -> {
      if (before == null) {
        return new UiModel.SeparatorModel("HEADER");
      } else if (after == null) {
        return new UiModel.SeparatorModel("FOOTER");
      } else if (shouldSeparate(before, after)) {
        return new UiModel.SeparatorModel("BETWEEN ITEMS "
          + before.toString() + " AND " + after.toString());
      } else {
        // Return null to avoid adding a separator between two
        // items.
        return null;
      }
    });
});

জাভা

// Map outer stream, so you can perform transformations on each
// paging generation.
Transformations.map(PagingLiveData.getLiveData(pager),
  pagingData -> {
    // First convert items in stream to UiModel.UserModel.
    PagingData<UiModel> uiModelPagingData = pagingData.map(
      UiModel.UserModel::new);

    // Insert UiModel.SeparatorModel, which produces PagingData of
    // generic type UiModel.
    return PagingData.insertSeparators(uiModelPagingData,
      (@Nullable UiModel before, @Nullable UiModel after) -> {
        if (before == null) {
          return new UiModel.SeparatorModel("HEADER");
        } else if (after == null) {
          return new UiModel.SeparatorModel("FOOTER");
        } else if (shouldSeparate(before, after)) {
          return new UiModel.SeparatorModel("BETWEEN ITEMS "
            + before.toString() + " AND " + after.toString());
        } else {
          // Return null to avoid adding a separator between two
          // items.
          return null;
        }
      });
  });

UI এ বিভাজক হ্যান্ডেল করুন

বিভাজক আইটেম টাইপ মিটমাট করার জন্য আপনার UI পরিবর্তন করা চূড়ান্ত পদক্ষেপ। আপনার বিভাজক আইটেমগুলির জন্য একটি লেআউট এবং একটি ভিউ হোল্ডার তৈরি করুন এবং RecyclerView.ViewHolder এর ভিউ হোল্ডার টাইপ হিসাবে ব্যবহার করতে তালিকা অ্যাডাপ্টারটি পরিবর্তন করুন যাতে এটি একাধিক ধরণের ভিউ হোল্ডার পরিচালনা করতে পারে। বিকল্পভাবে, আপনি একটি সাধারণ বেস ক্লাস সংজ্ঞায়িত করতে পারেন যা আপনার আইটেম এবং বিভাজক ভিউ হোল্ডার ক্লাস উভয়ই প্রসারিত করে।

এছাড়াও আপনাকে আপনার তালিকা অ্যাডাপ্টারে নিম্নলিখিত পরিবর্তনগুলি করতে হবে:

  • বিভাজক তালিকা আইটেমগুলির জন্য অ্যাকাউন্টের জন্য onCreateViewHolder() এবং onBindViewHolder() পদ্ধতিতে কেস যোগ করুন।
  • একটি নতুন তুলনামূলক প্রয়োগ করুন।

কোটলিন

class UiModelAdapter :
  PagingDataAdapter<UiModel, RecyclerView.ViewHolder>(UiModelComparator) {

  override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int
  ) = when (viewType) {
    R.layout.item -> UserModelViewHolder(parent)
    else -> SeparatorModelViewHolder(parent)
  }

  override fun getItemViewType(position: Int) {
    // Use peek over getItem to avoid triggering page fetch / drops, since
    // recycling views is not indicative of the user's current scroll position.
    return when (peek(position)) {
      is UiModel.UserModel -> R.layout.item
      is UiModel.SeparatorModel -> R.layout.separator_item
      null -> throw IllegalStateException("Unknown view")
    }
  }

  override fun onBindViewHolder(
    holder: RecyclerView.ViewHolder,
    position: Int
  ) {
    val item = getItem(position)
    if (holder is UserModelViewHolder) {
      holder.bind(item as UserModel)
    } else if (holder is SeparatorModelViewHolder) {
      holder.bind(item as SeparatorModel)
    }
  }
}

object UiModelComparator : DiffUtil.ItemCallback<UiModel>() {
  override fun areItemsTheSame(
    oldItem: UiModel,
    newItem: UiModel
  ): Boolean {
    val isSameRepoItem = oldItem is UiModel.UserModel
      && newItem is UiModel.UserModel
      && oldItem.id == newItem.id

    val isSameSeparatorItem = oldItem is UiModel.SeparatorModel
      && newItem is UiModel.SeparatorModel
      && oldItem.description == newItem.description

    return isSameRepoItem || isSameSeparatorItem
  }

  override fun areContentsTheSame(
    oldItem: UiModel,
    newItem: UiModel
  ) = oldItem == newItem
}

জাভা

class UiModelAdapter extends PagingDataAdapter<UiModel, RecyclerView.ViewHolder> {
  UiModelAdapter() {
    super(new UiModelComparator(), Dispatchers.getMain(),
      Dispatchers.getDefault());
  }

  @NonNull
  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
    int viewType) {
    if (viewType == R.layout.item) {
      return new UserModelViewHolder(parent);
    } else {
      return new SeparatorModelViewHolder(parent);
    }
  }

  @Override
  public int getItemViewType(int position) {
    // Use peek over getItem to avoid triggering page fetch / drops, since
    // recycling views is not indicative of the user's current scroll position.
    UiModel item = peek(position);
    if (item instanceof UiModel.UserModel) {
      return R.layout.item;
    } else if (item instanceof UiModel.SeparatorModel) {
      return R.layout.separator_item;
    } else {
      throw new IllegalStateException("Unknown view");
    }
  }

  @Override
  public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,
    int position) {
    if (holder instanceOf UserModelViewHolder) {
      UserModel userModel = (UserModel) getItem(position);
      ((UserModelViewHolder) holder).bind(userModel);
    } else {
      SeparatorModel separatorModel = (SeparatorModel) getItem(position);
      ((SeparatorModelViewHolder) holder).bind(separatorModel);
    }
  }
}

class UiModelComparator extends DiffUtil.ItemCallback<UiModel> {
  @Override
  public boolean areItemsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    boolean isSameRepoItem = oldItem instanceof UserModel
      && newItem instanceof UserModel
      && ((UserModel) oldItem).getId().equals(((UserModel) newItem).getId());

    boolean isSameSeparatorItem = oldItem instanceof SeparatorModel
      && newItem instanceof SeparatorModel
      && ((SeparatorModel) oldItem).getDescription().equals(
      ((SeparatorModel) newItem).getDescription());

    return isSameRepoItem || isSameSeparatorItem;
  }

  @Override
  public boolean areContentsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    return oldItem.equals(newItem);
  }
}

জাভা

class UiModelAdapter extends PagingDataAdapter<UiModel, RecyclerView.ViewHolder> {
  UiModelAdapter() {
    super(new UiModelComparator(), Dispatchers.getMain(),
      Dispatchers.getDefault());
  }

  @NonNull
  @Override
  public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
    int viewType) {
    if (viewType == R.layout.item) {
      return new UserModelViewHolder(parent);
    } else {
      return new SeparatorModelViewHolder(parent);
    }
  }

  @Override
  public int getItemViewType(int position) {
    // Use peek over getItem to avoid triggering page fetch / drops, since
    // recycling views is not indicative of the user's current scroll position.
    UiModel item = peek(position);
    if (item instanceof UiModel.UserModel) {
      return R.layout.item;
    } else if (item instanceof UiModel.SeparatorModel) {
      return R.layout.separator_item;
    } else {
      throw new IllegalStateException("Unknown view");
    }
  }

  @Override
  public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,
    int position) {
    if (holder instanceOf UserModelViewHolder) {
      UserModel userModel = (UserModel) getItem(position);
      ((UserModelViewHolder) holder).bind(userModel);
    } else {
      SeparatorModel separatorModel = (SeparatorModel) getItem(position);
      ((SeparatorModelViewHolder) holder).bind(separatorModel);
    }
  }
}

class UiModelComparator extends DiffUtil.ItemCallback<UiModel> {
  @Override
  public boolean areItemsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    boolean isSameRepoItem = oldItem instanceof UserModel
      && newItem instanceof UserModel
      && ((UserModel) oldItem).getId().equals(((UserModel) newItem).getId());

    boolean isSameSeparatorItem = oldItem instanceof SeparatorModel
      && newItem instanceof SeparatorModel
      && ((SeparatorModel) oldItem).getDescription().equals(
      ((SeparatorModel) newItem).getDescription());

    return isSameRepoItem || isSameSeparatorItem;
  }

  @Override
  public boolean areContentsTheSame(@NonNull UiModel oldItem,
    @NonNull UiModel newItem) {
    return oldItem.equals(newItem);
  }
}

নকল কাজ এড়িয়ে চলুন

এড়ানোর জন্য একটি মূল সমস্যা হল অ্যাপটিকে অপ্রয়োজনীয় কাজ করা। ডেটা আনা একটি ব্যয়বহুল অপারেশন, এবং ডেটা রূপান্তরও মূল্যবান সময় নিতে পারে। একবার ডেটা লোড হয়ে গেলে এবং UI-তে প্রদর্শনের জন্য প্রস্তুত হয়ে গেলে, কনফিগারেশন পরিবর্তনের ক্ষেত্রে এবং UI পুনরায় তৈরি করার প্রয়োজন হলে এটি সংরক্ষণ করা উচিত।

cachedIn() অপারেশন এর আগে ঘটে যাওয়া যেকোনো রূপান্তরের ফলাফল ক্যাশে করে। অতএব, cachedIn() আপনার ভিউমডেলের শেষ কল হওয়া উচিত।

কোটলিন

pager.flow // Type is Flow<PagingData<User>>.
  .map { pagingData ->
    pagingData.filter { user -> !user.hiddenFromUi }
      .map { user -> UiModel.UserModel(user) }
  }
  .cachedIn(viewModelScope)

জাভা

// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
PagingRx.cachedIn(
  // Type is Flowable<PagingData<User>>.
  PagingRx.getFlowable(pager)
    .map(pagingData -> pagingData
      .filter(user -> !user.isHiddenFromUi())
      .map(UiModel.UserModel::new)),
  viewModelScope);
}

জাভা

// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
PagingLiveData.cachedIn(
  Transformations.map(
    // Type is LiveData<PagingData<User>>.
    PagingLiveData.getLiveData(pager),
    pagingData -> pagingData
      .filter(user -> !user.isHiddenFromUi())
      .map(UiModel.UserModel::new)),
  viewModelScope);

PagingData এর একটি স্ট্রিমের সাথে cachedIn() ব্যবহার করার বিষয়ে আরও তথ্যের জন্য, পেজিং ডেটার একটি স্ট্রিম সেট আপ করুন দেখুন।

অতিরিক্ত সম্পদ

পেজিং লাইব্রেরি সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত সংস্থানগুলি দেখুন:

কোডল্যাব

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}