问题描述
我的设置可以正常使用:用户单击对话,列表打开,其中包含该对话的所有消息,按最新的顺序排列。
ConversationFragment
@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);
}
Conversationviewmodel
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()
);
}
ConversationRepository
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);
}
MessageDao
@Query(
"SELECT * FROM Message " +
"WHERE Message.conversationId = :conversationId " +
"ORDER BY Message.time DESC"
)
public abstract PagingSource<Integer,Itemmessage> getMessageList(String conversationId);
现在我的目标是能够打开已经在特定消息上滚动的对话。
我也不想加载整个对话,然后滚动到该消息,某些对话可能会很长,并且我不想让用户进入自动滚动过程,因为要花很长时间才能到达特定的消息。 / p>
理想情况下,我认为此操作正确的方法是传递消息ID以供查看,在该消息ID之前和之后加载周围的X条消息,然后在{{ 1}},如果用户上下移动,它将加载更多内容。
这并不意味着使用网络请求,整个对话已经在数据库中可用,因此它将仅使用数据库中已经存在的信息。
我尝试理解使用RecyclerView
或ItemKeyedDataSource
的示例,但是我无处可去,因为每次这些示例仅在Kotlin中使用,并且需要翻新才能使用,因此我不使用。因为这些示例对于像我这样使用Java而不使用Retrofit的任何人都是完全没有用的。
如何实现?
请提供Java语言的答案,而不仅限于Kotlin(只要在Java语言中也可以使用kotlin就可以了),请不要建议新的库。
解决方法
据我所知,官方文档并未提供有关如何解决此问题的任何线索,以实现分页+会议室集成。实际上,它没有提供任何解决方案来PagingDataAdapter
期间滚动到某个项目。
到目前为止,对我而言唯一有效的方法是我希望每次都执行两次查询:一项是在结果查询列表中查找项目位置,另一项是使用{{1 }}在initialKey
构造函数中设置为我们先前查询的项目位置的值。
如果您感到有些困惑,这里就不结束了,因为甚至没有记录什么是Pager
及其用法。不,很认真:What does the initialKey parameter do in the Pager constructor
因此,这里有两个猜谜游戏:一种找到从结果列表中查找项目索引的正确方法,另一种在最终查询中正确设置它。
我希望Paging 3文档能尽快得到改进,以涵盖这些非常基本的问题。
最后,这是一个示例,说明了我如何设法解决此问题,即使我不知道这是否是正确的解决方法,因为同样,他们的文档绝对缺少部门。
- 为所需的列表结果创建两个相同的查询
- 这些查询中的一个仅根据您用来唯一标识项目的键返回结果的完整列表。在我的情况下是
initialKey
。 - 以2加载查询,并使用
messageId
循环逐个迭代结果列表,直到找到要知道其在列表中位置的项目。该位置由您在循环块中使用的迭代器确定。 - 将3中的商品位置作为
for...
参数传递到最终查询的initialKey
构建器中 - 您现在将收到的第一批数据将包含您想要的项目
- 如果需要,现在可以滚动到
Pager
中的该项目,但是必须从适配器中加载的当前项目列表中进行查询。请参见在RecyclerView
中使用
.snapshot()
就是这样,现在我终于可以使用Paging 3 + Room在某个位置加载项目了,由于完全没有相关文档,所以绝对不知道这是否是正确的处理方式。