[英]Boundary Callback (Android Paging Library) with CoroutineScope
[英]Paging library - Boundary callback for network + db with API taking page and size
簡短的問題:
使用使用頁面 + 大小加載新頁面和BoundaryCallback
類的 API,從架構組件處理分頁庫上的數據庫 + 網絡的正確方法是什么?
研究解釋
目前,在體系結構組件的分頁庫中使用的類BoundaryCallback
接收列表中元素的實例作為參數,而沒有該元素所在位置的實際上下文。 它發生在onItemAtFrontLoaded
和onItemAtEndLoaded
。
我的 Api 應該接收頁面和頁面大小以加載下一個數據塊。 作為分頁列表構建器的一部分添加的邊界回調應該根據預取距離和頁面大小告訴您何時加載下一頁數據。
由於 Api 需要提供頁碼和頁面大小,因此我沒有看到僅通過從onItemAtFrontLoaded
和onItemAtEndLoaded
提供的列表中接收一個元素來將其發送到 Api 的onItemAtEndLoaded
。 檢查此鏈接中的 google 示例,他們使用最后一個元素的名稱來獲取下一個元素,但這不適合具有頁面 + 大小的 Api。
他們還有另一個僅使用PagedKeyedDatasource
網絡PagedKeyedDatasource
,但沒有關於如何將其與數據庫和 BoundaryCallback 混合的示例或線索。
編輯:到目前為止,我發現的唯一解決方案是將最后加載的頁面存儲在共享首選項中,但這聽起來像是一個骯臟的把戲。
參考https://github.com/googlesamples/android-architecture-components/issues/252#issuecomment-392119468官方輸入。
文檔對這個問題有這樣的說法:
如果您沒有使用 item-keyed 網絡 API,您可能正在使用 page-keyed 或 page-indexed。 如果是這種情況,分頁庫不知道 BoundaryCallback 中使用的頁面鍵或索引,因此您需要自己跟蹤它。 您可以通過以下兩種方式之一執行此操作:
本地存儲頁面鍵
如果您想完美地恢復您的查詢,即使應用程序被終止並恢復,您也可以將密鑰存儲在磁盤上。 請注意,使用位置/頁面索引網絡 API,有一種簡單的方法可以做到這一點,即使用 listSize 作為下一次加載的輸入(或 listSize / NETWORK_PAGE_SIZE,用於頁面索引)。 但是,當前列表大小不會傳遞給 BoundaryCallback。 這是因為 PagedList 不一定知道本地存儲中的項目數。 占位符可能被禁用,或者數據源可能不計算項目總數。
相反,對於這些位置情況,您可以查詢數據庫中的項目數,並將其傳遞給網絡。
內存頁面鍵
如果您獲取的最后一頁是在數小時或數天前加載的,那么從網絡查詢下一頁通常沒有意義。 如果您將密鑰保存在內存中,則可以在從網絡源開始分頁時隨時刷新。 將下一個鍵存儲在內存中,在您的 BoundaryCallback 內。 在新建PagedList的LiveData/Observable時新建BoundaryCallback,刷新數據。 例如,在 Paging Codelab 中,GitHub 網絡頁面索引存儲在內存中。
並鏈接到示例 Codelab: https : //codelabs.developers.google.com/codelabs/android-paging/index.html#8
我有一個類似的 API(pageNum + size),我的data class
有 2 個額外的字段, pageNum
和pageSize
分別具有默認值1
和PAGE_SIZE
。
如果您使用Network+DB
,那么你就已經onZeroItemsLoaded
和onItemAtEndLoaded
,在onZeroItemsLoaded
發送pageNum
和pageSize
,因為它是在onItemAtEndLoaded
增量的pageSize由1
然后發送。
假設您有一個方法fetchData(pageNum, pageSize)
當您收到結果時,只需在此頁面的每個項目中相應地更新pageNum
和pageSize
。
我實現了這個:
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;
}
假設您總是從服務器獲取每頁N=10
項目,然后將其存儲在 db 中。 您可以使用 sql 查詢SELECT COUNT(*) FROM tbl
獲取數據庫中的項目數並將其存儲在變量count
。 現在要獲取接下來應該請求的頁碼,請使用:
val nextPage: Int = (count / N) + 1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.