分页库-具有API的页面和大小的网络+数据库的边界回调


71

简短问题

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

研究与解释

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

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

由于API需要的页码和页面提供的尺寸,我没有看到一个方法只是通过接收从列表中提供的要素之一发送到APIonItemAtFrontLoadedonItemAtEndLoaded。检查此链接中的google示例,它们使用最后一个元素的名称来获取下一个元素,但这不适合页面+大小的Api。

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

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

请参阅 https://github.com/googlesamples/android-architecture-components/issues/252#issuecomment-392119468以获得官方信息。


真正的问题是,如果你有服务器端的新元素,在页面的每个项目是在将转移。您能否将pageIndex基于API的API可靠地长期缓存到数据库中?
EpicPandaForce

如果元素按时间排序(最近的最后一页),或者像我这样,则每天生成一次不变的生成的提要是可能的。在多个应用程序中,基于大小+页数的页面索引很有意义,而且我已经看到许多API实现了这种模式
droidpl

不,只有官方支持评论中的一个
droidpl

取决于API响应是否传递元数据,例如pagepages。当它使用键来获取下一页时,这似乎针对noSQL进行了优化-而对于SQL而言,这并不一定有意义……并且遵循GitHub注释中的逻辑;如果同时删除了密钥怎么办?
Martin Zeitler '18

从现在开始,您是否找到任何解决方案?
dariush f

Answers:


1

文件中有这样一段对这个问题说:

如果您不使用项目键控网络API,则可能正在使用页面键控或页面索引。如果是这种情况,则分页库不知道BoundaryCallback中使用的页键或索引,因此您需要自己对其进行跟踪。您可以通过以下两种方式之一进行操作:

本地存储页面键

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

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

内存页面键

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

并链接到示例代码实验室:https : //codelabs.developers.google.com/codelabs/android-paging/index.html#8


1

我有一个类似的API(页次+大小),我有我的2名额外的字段data classpageNumpageSize使用默认值1PAGE_SIZE分别。

如果你使用Network+DB 那么你就必须onZeroItemsLoadedonItemAtEndLoaded,在onZeroItemsLoaded发送pageNumpageSize,因为它是在onItemAtEndLoaded增量的pageSize通过1,然后发送。

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


当您终止应用程序并随后将其打开并从数据库加载数据时会发生什么?pageNum无效...
NikolaSrdoč20年

1
我将pageNum作为表中的一个字段,因此当您终止应用程序并重新打开(如果Db为空)时,将调用onZeroItem,请使用pageNum = 1,pageSize = PAGE_SIZE,并且如果调用了onItemAtEndLoaded(您还将获得最后一个项目作为此方法中的参数),请使用DB中最后一项的(pageNum + 1)。
Kashish Sharma

感谢您的澄清,我一开始并不理解。在我的示例中,这意味着要迭代通过一个api响应页面返回的20个项目,并在插入db之前将pageNum设置为每个项目。那似乎不是一个很好的解决方案。我在使用observeForever监听具有页码的单独实体时感到困惑。 链接 虽然不知道这是否是一个好方法...
NikolaSrdoč20年

我不认为在异步执行时迭代20个以上的项目并不昂贵(以及可能也是异步的API调用)。但最终,这取决于您。您可以使用更多方法,例如自动递增表中的pageNum字段,然后计算pageNum,只需使用PAGE_SIZE对其取MOD,然后加1(可能需要在此处和此处进行调整)。编辑:刚刚看到您也在开发电影应用程序,则可以使用我上面讨论的相同方法来检查我的github.com/Kashish-Sharma/TheMovieDBApp
Kashish Sharma

很好,请当我被卡住时请把它留作参考。谢谢。
NikolaSrdoč20年

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;
}

0

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

val nextPage: Int = (count / N) + 1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.