72 votes

Bibliothèque de pagination - Rappel de limite pour le réseau + db avec API prenant la page et la taille

Question brève :

Quelle est la bonne façon de gérer la base de données + le réseau sur la bibliothèque Paging des composants de l'architecture, en utilisant une API qui utilise la taille de la page + pour charger une nouvelle page et l'icône BoundaryCallback classe ?

Recherche et explication

Actuellement, la classe BoundaryCallback utilisé dans la bibliothèque de pagination des composants d'architecture, reçoit comme paramètre l'instance d'un élément de la liste sans contexte réel de l'endroit où se trouve cet élément. Cela se produit dans onItemAtFrontLoaded y onItemAtEndLoaded .

Mon Api est censé recevoir la page et la taille de la page pour charger le prochain morceau de données. La fonction de rappel Boundary, ajoutée dans le cadre de la construction de la liste paginée, est censée vous indiquer quand charger la page de données suivante en fonction de la distance de préextraction et de la taille de la page.

Puisque l'Api a besoin du numéro de page et de la taille de la page à fournir, je ne vois pas comment envoyer cela à l'Api en recevant simplement un des éléments de la liste comme proposé dans onItemAtFrontLoaded y onItemAtEndLoaded . Vérifier les exemples de google dans ce lien En effet, ils utilisent le nom du dernier élément pour obtenir le suivant, mais cela ne correspond pas à une Api avec page + taille.

Ils ont également un autre exemple avec un seul réseau qui utilise PagedKeyedDatasource mais il n'y a pas d'exemple ou d'indice sur la façon de combiner cela avec la base de données et le BoundaryCallback.

Editar : Les seules solutions que j'ai trouvées jusqu'à présent sont de stocker la dernière page chargée sur les préférences partagées, mais cela semble être un sale tour.

Se référer à https://github.com/googlesamples/Android-architecture-components/issues/252#issuecomment-392119468 pour une contribution officielle à ce sujet.

0 votes

El real Le problème est que si vous avez de nouveaux éléments côté serveur, la page sur laquelle se trouvait chaque élément va se déplacer. Pouvez-vous mettre en cache de manière fiable un pageIndex -dans la base de données à long terme ?

0 votes

C'est possible si les éléments sont classés par ordre chronologique (dernière page la plus récente), ou comme dans mon cas, un flux généré qui reste inchangé une fois par jour. Il existe de nombreuses applications pour lesquelles l'indexation des pages basée sur la taille + le numéro de page a du sens, et j'ai vu de nombreuses API mettant en œuvre ce modèle.

0 votes

Non, seulement celui qui figure dans le commentaire du support officiel.

1voto

user8468173 Points 136

J'ai une API similaire (pageNum + taille), j'ai 2 champs supplémentaires dans mon API. data class , pageNum y pageSize avec des valeurs par défaut 1 y PAGE_SIZE respectivement.

Si vous utilisez Network+DB alors vous aurez onZeroItemsLoaded y onItemAtEndLoaded , Sur onZeroItemsLoaded envoyer pageNum y pageSize tel qu'il est, et dans onItemAtEndLoaded incrémenter pageSize de 1 et ensuite envoyer.

Disons que vous avez une méthode fetchData(pageNum, pageSize) lorsque vous recevez le résultat de cette opération, il suffit de mettre à jour le pageNum y pageSize en conséquence dans chaque rubrique de cette page.

1voto

Luke Points 577

El documentation a ceci à dire sur la question :

Si vous n'utilisez pas une API de réseau à clé d'élément, vous pouvez utiliser une API à clé de page ou une API indexée par page. page-keyed, ou page-indexed. Si c'est le cas, la bibliothèque de pagination ne connaît pas la clé ou l'index de page utilisé dans le BoundaryCallback, Vous devez donc le faire vous-même. Vous pouvez le faire de deux façons :

Stockage local Clé de page

Si vous voulez reprendre parfaitement votre requête, même si l'application est tuée et reprise, vous pouvez stocker la clé sur le disque. Notez qu'avec une API de réseau à indexation positionnelle/de page, il existe une simple fonction moyen simple de le faire, en utilisant la listSize comme entrée pour le prochain chargement (ou listSize / NETWORK_PAGE_SIZE, pour l'indexation des pages). La taille actuelle de la liste n'est pas transmise à la BoundaryCallback. Ceci est dû au fait que la PagedList ne connaît pas nécessairement le nombre d'éléments en mémoire locale. local. Les placeholders peuvent être désactivés, ou la source de données peut ne pas compter le nombre total d'éléments. le nombre total d'éléments.

Au lieu de cela, pour ces cas de position, vous pouvez interroger la base de données pour obtenir le nombre d'articles, et le transmettre au réseau.

Clé de page en mémoire

Souvent, cela n'a pas de sens d'interroger la page suivante suivante à partir du réseau si la dernière page que vous avez extraite a été chargée plusieurs heures ou jours auparavant. jours auparavant. Si vous gardez la clé en mémoire, vous pouvez rafraîchir la page à chaque fois que vous commencez à paginer à partir d'une source réseau. vous pouvez rafraîchir chaque fois que vous commencez à paginer à partir d'une source réseau. Stockez la clé suivante en mémoire, dans votre BoundaryCallback. Lorsque vous créez un nouveau BoundaryCallback lorsque vous créez un nouveau LiveData/Observable de PagedList, rafraîchissez les données. Par exemple, dans le Codelab Paging, l'index de la page réseau GitHub est stocké en mémoire.

Et des liens vers un exemple de Codelab : https://codelabs.developers.google.com/codelabs/Android-paging/index.html#8

0voto

user3795295 Points 27

Je le mets en œuvre :

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

0voto

realpac Points 291

Disons que vous allez toujours chercher N=10 les éléments par page à partir du serveur, puis les stocker dans la base de données. Vous pouvez obtenir le nombre d'éléments dans la base de données en utilisant la requête sql suivante SELECT COUNT(*) FROM tbl et le stocker dans la variable count . Maintenant, pour obtenir le numéro de la page qui doit être demandée ensuite, utilisez :

val nextPage: Int = (count / N) + 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X