【发布时间】:2020-11-12 21:03:01
【问题描述】:
我有一个消息列表。 每条消息都有一个唯一的 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 消息,然后在 @987654326 中已将其呈现给用户之后@如果用户上升或下降,它会加载更多。
这并不意味着使用网络请求,整个会话已经在数据库中可用,因此它只会使用数据库中已经存在的信息。
我已经尝试理解使用 ItemKeyedDataSource 或 PageKeyedDataSource 的示例,但我无处可去,因为每次这些示例都仅在 Kotlin 中并且需要 Retrofit 才能工作,而我不使用。因为这些示例对于像我这样使用 Java 且不使用 Retrofit 的人来说完全没用。
如何做到这一点?
请用 Java 提供答案,而不仅仅是 Kotlin(只要它也在 java 中,kotlin 就可以)并且请不要建议新的库。
【问题讨论】:
-
REFRESH配置
LoadParams.key的方式是在Pager中修改initialKey或者实现PagingSource.getRefreshKey(后续调用)。不幸的是,由于 Room 的PagingSource是位置键控,这可能有点难以实现(可能更容易将平面映射到动态查询)。在这种情况下,我可能只是建议直接实现您自己的项目,键入PagingSource,然后您可以简单地将您正在加载的项目直接传递给 Pager 中的initialKey -
@dlam 感谢您的指点,但我完全迷路了。你能指出我在哪里可以学习如何做你的第二个建议吗?实现我自己的项目,键入
PagingSource。 -
@dlam 我发现最接近你的建议的是这个developer.android.com/reference/kotlin/androidx/paging/…,但它只是展示了如何使用改造来做到这一点。我没有使用 Retrofit,实际上我只是想从 Room DB 本身加载数据,而该文档对此毫无意义。我对整个 Paging 3 文档完全不知所措。
-
@dlam 我无法使用我找到的可用信息找到任何可行的解决方案。我无法理解如何指示
getRefreshKey,在寻呼机中使用不同的初始键,也无法理解如何实现我自己的键控PagingSource的项目。你能提供一些有用的例子吗? -
忘了说我的基本原理有多远:获取项目在数据库结果列表中的位置,计算该项目位于哪个页面并将该页码用作
initialKey。我也试图理解你所说的flatMap to a dynamic query是什么意思,但也没有运气。
标签: android android-room android-paging android-paging-3