【问题标题】:Paging 3: How to load list at item position or at item with specific id分页 3:如何在项目位置或具有特定 ID 的项目加载列表
【发布时间】: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 中已将其呈现给用户之后@如果用户上升或下降,它会加载更多。

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

我已经尝试理解使用 ItemKeyedDataSourcePageKeyedDataSource 的示例,但我无处可去,因为每次这些示例都仅在 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


【解决方案1】:

据我所知,官方文档没有提供任何关于如何解决 Paging + Room 集成的线索。事实上,它没有提供任何解决方案来滚动到 PagingDataAdapter 句号中的项目。

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

如果您感到有点困惑,这并没有到此结束,因为即使是关于什么是 initialKey 以及如何使用它的解释也没有记录在案。不,说真的:What does the initialKey parameter do in the Pager constructor

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-02
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多