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

Sha*_*dow 5 android android-room android-paging android-paging-3

我有一个消息列表。每条消息都有一个唯一的 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);

    }
Run Code Online (Sandbox Code Playgroud)

对话视图模型


    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()
        );
    }
Run Code Online (Sandbox Code Playgroud)

对话库

    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);
    }
Run Code Online (Sandbox Code Playgroud)

消息道

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

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

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

理想情况下,我设想正确完成此操作的方法是将消息 id 传递到视图中,在该消息 id 之前和之后加载围绕该消息 id 的一大块 X 消息,然后在它已经呈现给用户之后,RecyclerView如果用户向上或向下。

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

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

如何才能实现这一目标?

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

Sha*_*dow 3

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

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

如果您感到有点困惑,这并没有结束,因为甚至连它是什么initialKey以及如何使用它的解释都没有记录。不,说真的:Pager 构造函数中的initialKey 参数有什么作用

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

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

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

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

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