分页 3:如何在项目位置或具有特定 ID 的项目加载列表



我有一个消息列表。 每条消息都有一个唯一的 GUID。

我的设置适用于正常使用:用户单击对话,列表打开,其中包含属于该对话的所有消息,按最近的顺序排序。

对话片段


@Override
public void onViewCreated(
@NonNull View view,
@Nullable Bundle savedInstanceState
) {
LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
viewModel = new ViewModelProvider(this).get(ConversationViewModel.class);
viewModel
.getMessageList(lifecycleOwner, conversationId) // conversationId is a global variable
.observe(lifecycleOwner, messagePagingData -> adapter.submitData(
lifecycleOwner.getLifecycle(),
messagePagingData 
));
super.onViewCreated(view, savedInstanceState);
}

对话视图模型


final PagingConfig pagingConfig = new PagingConfig(10, 10, false, 20);
private final ConversationRepository conversationRepository;
public ConversationViewModel(@NonNull Application application) {
super(application);
conversationRepository = new ConversationRepository(application);
}
public LiveData<PagingData<ItemMessage>> getMessageList(
@NonNull LifecycleOwner lifecycleOwner,
@NonNull String conversationId
) {
return PagingLiveData.cachedIn(
PagingLiveData.getLiveData(new Pager<>(pagingConfig, () -> conversationRepository.getMessageList(conversationId))),
lifecycleOwner.getLifecycle()
);
}

对话存储库

private final MessageDao messageDao;
public ConversationRepository(@NonNull Context context) {
AppDatabase database = AppDatabase.getDatabase(context);
messageDao = database.messageDao();
}
public PagingSource<Integer, ItemMessage> getMessageList(@NonNull String conversationId) {
return messageDao.getMessageList(conversationId);
}

留言道

@Query(
"SELECT * FROM Message " +
"WHERE Message.conversationId = :conversationId " +
"ORDER BY Message.time DESC"
)
public abstract PagingSource<Integer, ItemMessage> getMessageList(String conversationId);

现在我的目标是能够打开已经滚动到特定消息的对话。

我也不想加载整个对话然后滚动到消息,有些对话可能很长,我不想让用户自动滚动,这可能需要很长时间才能到达特定消息。

理想情况下,我设想正确完成此操作的方式是传递消息 ID 以显示在视图中,在该消息 ID 之前和之后加载一大块 X 消息,然后在它已经在RecyclerView中呈现给用户之后,如果用户上升或下降,它将加载更多。

这并不意味着使用网络请求,整个会话已经在数据库中可用,因此它将仅使用数据库中已有的信息。

我尝试理解使用ItemKeyedDataSourcePageKeyedDataSource的示例,但我无处可去,因为每次这些示例都只在 Kotlin 中并且需要 Retrofit 才能工作,而我不使用。因为这些例子对于像我这样使用 Java 并且不使用 Retrofit 的人来说是完全无用的。

如何实现这一点?

请在 Java 中提供答案,而不仅仅是 Kotlin(只要 Kotlin 也在 Java 中就可以),并且请不要建议新的库。

据我所知,官方文档没有提供任何有关如何解决寻呼+房间集成的线索。事实上,它没有提供任何解决方案来滚动到PagingDataAdapter期间的项目。

到目前为止,唯一对我有用的事情是每次我希望完成此操作时都运行两个查询:一个用于查找结果查询列表中的项目位置,另一个用于实际加载所述列表,其中包含在Pager构造函数中设置的initialKey,以及我们之前查询的项目位置的值。

如果你感到有点困惑,这并没有就此结束,因为即使是关于initialKey什么以及如何使用它的解释也没有记录下来。不,认真的:初始键参数在寻呼器构造函数中做什么

因此,这里有两个猜谜游戏:一个是找到从结果列表中查找项目索引的正确方法,另一个是在最终查询中正确设置它。

我希望分页 3 文档尽快得到改进,以涵盖这些非常基本的问题。

最后,这是我如何设法让这个问题为我工作的一个例子,即使我不知道这是否是正确的方法,因为同样,他们的文档在这个部门绝对缺乏。

  1. 为所需的列表结果创建两个相同的查询
  2. 其中一个查询仅根据用于唯一标识项目的键返回结果的完整列表。就我而言,它是messageId.
  3. 在 2 中加载查询,并使用for...循环单独迭代结果列表,直到找到想要知道其在列表中位置的项目。该位置由您在循环块中使用的迭代器给出。
  4. 将 3 中的项目位置作为initialKey参数传递到最终查询的Pager生成器中
  5. 您现在将收到的第一个数据块将包含您想要的项目
  6. 如果需要,现在可以滚动到RecyclerView中的该项目,但您必须从适配器中加载的当前项目列表中查询它。请参阅有关在PagingAdapter中使用.snapshot()的信息

就是这样,现在我终于可以使用 Paging 3 + Room 在某个位置加载一个项目,由于完全没有这方面的文档,我完全不知道这是否是正确的方法。

最新更新