android - realtime - Biblioteca de paginación-Devolución de llamada de límite para red+db con API que toma página y tamaño
firestore pricing (3)
Pregunta corta :
¿Cuál es la forma correcta de manejar la base de datos + red en la biblioteca de Paginación de los componentes de Arquitectura, usando una API que usa el tamaño de página + para cargar una nueva página y la clase
BoundaryCallback
?
Investigación y explicación
Actualmente, la clase
BoundaryCallback
utilizada en la biblioteca de paginación para los componentes de la arquitectura, recibe como parámetro la instancia de un elemento en la lista sin el contexto real de donde se encuentra este elemento.
Ocurre en
onItemAtFrontLoaded
y
onItemAtEndLoaded
.
Se supone que mi Api debe recibir la página y el tamaño de la página para cargar el siguiente fragmento de datos. Se supone que la devolución de llamada de límite, agregada como parte del generador de listas paginadas, le indica cuándo cargar la próxima página de datos según la distancia de captación previa y el tamaño de la página.
Dado que el Api necesita el número de página y el tamaño de la página para proporcionar, no veo una manera de enviarlo al Api simplemente recibiendo uno de los elementos de la lista tal como se ofrece en
onItemAtFrontLoaded
y
onItemAtEndLoaded
.
Al revisar los ejemplos de google en
este enlace
, usan el nombre del último elemento para obtener el siguiente, pero eso no encaja en una Api con página + tamaño.
También tienen otro ejemplo con solo una red que usa
PagedKeyedDatasource
, pero no hay ninguna muestra o pista sobre cómo mezclar eso con la base de datos y BoundaryCallback.
Edición : las únicas soluciones que he encontrado hasta ahora son almacenar la última página cargada en las preferencias compartidas, pero eso suena como un truco sucio.
Consulte https://github.com/googlesamples/android-architecture-components/issues/252#issuecomment-392119468 para obtener información oficial al respecto.
Digamos que siempre obtiene
N=10
elementos por página del servidor y luego los almacena en db.
Puede obtener el número de elementos en db utilizando la consulta SQL
SELECT COUNT(*) FROM tbl
y almacenarlo en el
count
variables.
Ahora para obtener el número de página que debe solicitarse a continuación, use:
val nextPage: Int = (count / N) + 1
La documentation tiene esto que decir sobre el tema:
Si no está utilizando una API de red con clave de elemento, puede que esté usando la clave de página o la página indexada. Si este es el caso, la biblioteca de paginación no conoce la clave de página o el índice utilizado en BoundaryCallback, por lo que debe rastrearlo usted mismo. Puedes hacer esto de una de dos maneras:
Página de almacenamiento local clave
Si desea reanudar perfectamente su consulta, incluso si la aplicación se cancela y reanuda, puede almacenar la clave en el disco. Tenga en cuenta que con una API de red de índice de posición / página, hay una forma sencilla de hacerlo, utilizando listSize como entrada para la siguiente carga (o listSize / NETWORK_PAGE_SIZE, para la indexación de páginas). Sin embargo, el tamaño de la lista actual no se pasa a BoundaryCallback. Esto se debe a que PagedList no necesariamente conoce la cantidad de elementos en el almacenamiento local. Los marcadores de posición pueden estar deshabilitados, o el DataSource no puede contar el número total de elementos.
En su lugar, para estos casos posicionales, puede consultar la base de datos para el número de elementos y pasarlo a la red.
Tecla de página en memoria
A menudo no tiene sentido consultar la siguiente página de la red si la última página que buscó se cargó muchas horas o días antes. Si mantiene la clave en la memoria, puede actualizarla cada vez que inicie la paginación desde una fuente de red. Guarde la siguiente clave en la memoria, dentro de su BoundaryCallback. Cuando cree un nuevo BoundaryCallback cuando cree un nuevo LiveData / Observable of PagedList, actualice los datos. Por ejemplo, en el Plab Codelab, el índice de la página de red de GitHub se almacena en la memoria.
Y enlaces a un ejemplo de Codelab: https://codelabs.developers.google.com/codelabs/android-paging/index.html#8
Yo implemento esto:
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;
}