72

简短的问题

使用使用页面+大小的API来加载新页面和BoundaryCallback类的API从架构组件处理分页库上的数据库+网络的正确方法是什么?

研究与解释

目前,BoundaryCallback用于架构组件的分页库中的类接收列表中元素的实例作为参数,而没有该元素所在位置的实际上下文。它发生在onItemAtFrontLoaded和中onItemAtEndLoaded

我的 Api 应该接收页面和页面大小以加载下一个数据块。作为分页列表构建器的一部分添加的边界回调应该告诉您何时根据预取距离和页面大小加载下一页数据。

由于 Api 需要提供页码和页面大小,因此我看不到仅通过接收列表中提供的元素之一来将其发送到 Api 的方法onItemAtFrontLoadedonItemAtEndLoaded检查此链接中的 google 示例,他们使用最后一个元素的名称来获取下一个元素,但这不适合带有页面 + 大小的 Api。

他们还有另一个仅使用网络的示例PagedKeyedDatasource,但没有关于如何将其与数据库和 BoundaryCallback 混合的示例或线索。

编辑:到目前为止,我发现的唯一解决方案是将最后加载的页面存储在共享首选项中,但这听起来像是一个肮脏的把戏。

有关官方输入,请参阅 https://github.com/googlesamples/android-architecture-components/issues/252#issuecomment-392119468

4

4 回答 4

1

我有一个类似的 API(pageNum + size),我的 , 中还有 2 个额外的字段data classpageNum分别pageSize具有默认值1PAGE_SIZE

如果您正在使用,Network+DB 那么您将拥有onZeroItemsLoadedand onItemAtEndLoaded,在onZeroItemsLoaded发送pageNumpageSize原样中,并以onItemAtEndLoadedpageSize 递增1然后发送。

假设您fetchData(pageNum, pageSize)在收到结果时有一个方法,只需在此页面的每个项目中相应地更新pageNum和。pageSize

于 2020-05-17T07:19:48.310 回答
1

文档对这个问题有这样的说法:

如果您没有使用 item-keyed 网络 API,您可能正在使用 page-keyed 或 page-indexed。如果是这种情况,分页库不知道 BoundaryCallback 中使用的页面键或索引,因此您需要自己跟踪它。您可以通过以下两种方式之一执行此操作:

本地存储页面键

如果您想完美地恢复您的查询,即使应用程序被杀死并恢复,您也可以将密钥存储在磁盘上。请注意,使用位置/页面索引网络 API,有一种简单的方法可以做到这一点,即使用 listSize 作为下一次加载的输入(或 listSize / NETWORK_PAGE_SIZE,用于页面索引)。但是,当前列表大小不会传递给 BoundaryCallback。这是因为 PagedList 不一定知道本地存储中的项目数。占位符可能被禁用,或者 DataSource 可能不计算项目总数。

相反,对于这些位置情况,您可以查询数据库中的项目数,并将其传递给网络。

内存页键

如果您获取的最后一页是在数小时或数天前加载的,那么从网络查询下一页通常是没有意义的。如果将密钥保存在内存中,则可以在从网络源开始分页时随时刷新。将下一个键存储在内存中,在 BoundaryCallback 中。当你在新建一个PagedList的LiveData/Observable时新建一个BoundaryCallback,刷新数据。例如,在 Paging Codelab 中,GitHub 网络页面索引存储在内存中。

并链接到示例 Codelab:https ://codelabs.developers.google.com/codelabs/android-paging/index.html#8

于 2019-07-03T13:46:58.453 回答
0

假设您总是N=10从服务器获取每页的项目,然后将其存储在数据库中。您可以使用 sql 查询获取 db 中的项目数SELECT COUNT(*) FROM tbl并将其存储在变量中count。现在要获取接下来应该请求的页码,请使用:

val nextPage: Int = (count / N) + 1
于 2019-01-06T17:52:15.727 回答
0

我实现了这个:

PagedList.BoundaryCallback<Produto> boundaryCallbackNovidades = new PagedList.BoundaryCallback<Produto>(){
    int proxPagina;
    boolean jaAtualizouInicio=false;

    public void onZeroItemsLoaded() {
        requestProdutos(
            webService.pesquisarNovidadesDepoisDe(LocalDateTime.now().format(Util.formatterDataTime), 0, 20));
    }

    public void onItemAtFrontLoaded(@NonNull Produto itemAtFront) {
        if(!jaAtualizouInicio)
            requestProdutos(
                webService.pesquisarNovidadesMaisRecentesQue(itemAtFront.data.format(Util.formatterDataTime)));
        jaAtualizouInicio=true;
    }

    public void onItemAtEndLoaded(@NonNull Produto itemAtEnd) {
        requestProdutos(
            webService.pesquisarNovidadesDepoisDe(LocalDateTime.now().format(Util.formatterDataTime), proxPagina++, 20));
    }
};


public LiveData<PagedList<Produto>> getNovidades(){
    if(novidades==null){
        novidades = new LivePagedListBuilder<>(produtoDao.produtosNovidades(),
                10)
                .setBoundaryCallback(boundaryCallbackNovidades)
                .build();
    }
    return novidades;
}
于 2018-12-28T00:13:52.250 回答