Библиотека пейджинга - Граничный обратный вызов для сети + db с API, использующим страницу и размер
Короткий вопрос:
Каков правильный способ обработки базы данных + сети в библиотеке Paging из компонентов архитектуры, используя API, который использует размер страницы + для загрузки новой страницы и класса BoundaryCallback
?
Исследования и объяснения
В настоящее время класс BoundaryCallback
используемый в библиотеке подкачки для компонентов архитектуры, получает в качестве параметра экземпляр элемента в списке без фактического контекста того, где находится этот элемент. Это происходит в onItemAtFrontLoaded
и onItemAtEndLoaded
.
Мой Api должен получать страницу и размер страницы для загрузки следующего фрагмента данных. Граничный обратный вызов, добавленный как часть построителя списков выведенных страниц, должен сообщать вам, когда загружать следующую страницу данных на основе расстояния предварительной выборки и размера страницы.
Поскольку Api нуждается в номере страницы и размере страницы для предоставления, я не вижу способа отправить это Api, просто получив один из элементов из списка, предложенный в onItemAtFrontLoaded
и onItemAtEndLoaded
. Проверяя примеры Google в этой ссылке, они используют имя последнего элемента для получения следующего, но это не соответствует Api с размером страницы +.
У них также есть другой пример с только сетью, которая использует PagedKeyedDatasource
, но нет образца или подсказки о том, как смешивать это с базой данных и BoundaryCallback.
Изменить: только решения, которые я нашел до сих пор, - это сохранить последнюю загруженную страницу в общих настройках, но это звучит как грязный трюк.
Обратитесь к https://github.com/googlesamples/android-architecture-components/issues/252#issuecomment-392119468 за официальный ввод.
Ответы
Ответ 1
Я реализую это:
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;
}
Ответ 2
Допустим, вы всегда выбираете N=10
элементов на страницу с сервера, а затем сохраняете их в дБ. Вы можете получить количество элементов в db, используя SQL-запрос SELECT COUNT(*) FROM tbl
и сохранить его в переменной count
. Теперь, чтобы получить номер страницы, которая должна быть запрошена далее, используйте:
val nextPage: Int = (count / N) + 1
Ответ 3
В документации есть что сказать по этому вопросу:
Если вы не используете сетевой API с ключом элемента, возможно, вы используете страницу с ключом или индексированную страницу. В этом случае библиотека подкачки не знает о ключе страницы или индексе, используемом в BoundaryCallback, поэтому вам нужно отследить его самостоятельно. Вы можете сделать это одним из двух способов:
Ключ страницы локального хранилища
Если вы хотите полностью возобновить запрос, даже если приложение было убито и возобновлено, вы можете сохранить ключ на диске. Обратите внимание, что с помощью сетевого API позиционного индекса/индекса страницы существует простой способ сделать это, используя listSize в качестве входных данных для следующей загрузки (или listSize/NETWORK_PAGE_SIZE для индексации страницы). Текущий размер списка не передается в BoundaryCallback. Это связано с тем, что PagedList не обязательно знает количество элементов в локальном хранилище. Заполнители могут быть отключены или DataSource может не учитывать общее количество элементов.
Вместо этого для этих позиционных случаев вы можете запросить в базе данных количество элементов и передать их в сеть.
Ключ страницы в памяти
Часто нет смысла запрашивать следующую страницу из сети, если последняя загруженная страница была загружена много часов или дней назад. Если вы храните ключ в памяти, вы можете обновлять его каждый раз, когда начинаете пейджинг из сетевого источника. Сохраните следующий ключ в памяти, внутри вашего BoundaryCallback. При создании нового BoundaryCallback при создании нового LiveData/Observable из PagedList обновите данные. Например, в Paging Codelab индекс сетевой страницы GitHub хранится в памяти.
И ссылки на пример Codelab: https://codelabs.developers.google.com/codelabs/android-paging/index.html#8
Ответ 4
Главное - сделать базу данных источником истины для данных, отображаемых пользовательским интерфейсом, и она поддерживается сетевыми запросами. BoundaryCallback имеет два метода: onZeroItemsLoaded(), который вызывается, когда в нашей базе данных есть нулевой элемент, и onItemAtEndLoaded(), который вызывается, когда мы достигаем последнего элемента в базе данных. в обоих случаях мы вызываем вспомогательный метод, который делает запрос сервера и сохраняет ответ в базе данных. после изменения содержимого базы данных LiveData выдает PagedList с полным результатом запроса, и вы можете настроить pagedList так, как вы хотите, создав его с помощью LivePagedListBuilder
проверьте этот обновленный codelab, поскольку он отвечает на все ваши вопросы