5 votes

Clarification du rappel des limites de la pagination Android

J'ai intégré le composant de pagination dans mon application et il fonctionne parfaitement bien (ou presque). J'ai Base de données + réseau modèle. La base de données contient initialement des éléments qui sont consommés par LivePagedListBuilder . J'observe ceci LiveData<PagedList<InboxEntity>> et, en fin de compte, transmettre la liste à PagedListAdapter#submitList(PagedList<T> pagedList) quelque chose comme :

LiveData<PagedList<Entity>> entities;
PagedList.Config pagedListConfig =
            (new PagedList.Config.Builder()).setEnablePlaceholders(true)
                .setPrefetchDistance(5)
                .setEnablePlaceholders(false)
                .setPageSize(10)
                .setInitialLoadSizeHint(10)
                .build();

entities = new LivePagedListBuilder<>(DAO.getItemList(), pagedListConfig)
entities.observe(this, new Observer<PagedList<Entity>>() {
            @Override
            public void onChanged(@Nullable PagedList<Entity> inboxEntities) {
                inboxAdapter.submitList(inboxEntities);
                isFirstLoad = false;
            }
        });

DAO#getItemList renvoie à DataSource.Factory<Integer, Entity> .

J'écoute le rappel de la limite et je déclenche un appel réseau lorsqu'il atteint la fin de la liste paginée. Cet appel alimente à nouveau la base de données.

Il y a encore une chose. J'ai enregistré AdapterDataObserver sur la vue du recycleur car si un élément a été inséré au début, je dois faire défiler jusqu'à la position supérieure :

RecyclerView.AdapterDataObserver adapterDataObserver = new RecyclerView.AdapterDataObserver() {
            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {

                if (positionStart == 0) {
                    layoutManager.scrollToPositionWithOffset(positionStart, 0);
                }
            }
        };

Je rencontre un problème avec ce modèle :

Après avoir effectué l'appel réseau, la base de données est à nouveau alimentée et onChanged est appelée avec une nouvelle PagedList<Entity> . Maintenant, est-ce que cette liste paginée contient uniquement les nouveaux éléments. Je l'ai confirmé.

Mais onItemRangeInserted est appelée avec positionStart comme 0 également, ce qui suggère que les éléments sont insérés au début. Mais ce n'est pas le cas. Ils sont insérés à la fin, ce qui a été confirmé par le stéthoscope de l'inspecteur.

Alors pourquoi le onItemRangeInserted étant appelé avec positionStart comme 0 ? Il m'est difficile de distinguer quand un nouvel élément est inséré au début de l'adaptateur et quand des éléments sont insérés à la fin.

Edita:

valeur de itemCount est de 10, ce qui correspond à la taille de ma page.

Dans DiffCallback, je compare simplement la colonne de clé primaire des deux entités en areItemsTheSame fonction.

0voto

2fours Points 1

C'est comme ça que je fais, ce n'est pas idéal mais ça marche. J'utilise une vue de recyclage avec le paramètre reverse défini sur true car il s'agit d'une application de chat. Vous devrez donc l'adapter à votre cas d'utilisation.

Dans votre fragment, créez un champ Timer :

private Timer mTimer;

Ajoutez un écouteur d'état de défilement qui définit un "id de la dernière ligne" que vous pouvez comparer plus tard.

 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    //Get the latest id when we started scrolling
                    AppExecutors.getInstance().databaseIO().execute(() ->
                            mLatestMessageId = mHomeViewModel.getMessageViewModel().getLatestMessageId(mOurUsername, mChatname));
                }
            }});

Utilisez l'AdapterDataObserver pour lancer une nouvelle minuterie lorsque l'insertion est appelée.

 private RecyclerView.AdapterDataObserver mAdapterDataObserver = new RecyclerView.AdapterDataObserver() {

        @Override
    public void onItemRangeInserted(int positionStart, int itemCount) {

        if (mTimer != null) {
            mTimer.cancel();
        }

        mTimer = new Timer();
        mTimer.schedule(new CheckNewMessageTimer(), 100);

    }
};

Voici la classe du timer, si de nouveaux éléments ont été insérés, le "latest row id" aura été incrémenté dans la base de données. Je ne fais défiler vers le bas que si je suis déjà en bas, sinon je change simplement la couleur d'un FAB "scroll to bottom" que j'ai.

  class CheckNewMessageTimer extends TimerTask {
        @Override
        public void run() {
            if (newItemsAdded()) {
                int firstItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition();

                boolean atBottom = firstItemPosition == 1;
                SurespotLog.d(TAG, "CheckNewMessageTimer, firstItemPosition: %d, atBottom: %b", firstItemPosition, atBottom);

                AppExecutors.getInstance().mainThread().execute(() -> {
                    if (atBottom) {
                        SurespotLog.d(TAG, "CheckNewMessageTimer, scrolling to bottom");
                        mListView.scrollToPosition(0);

                    }
                    else {
                        if (mFab != null) {
                            SurespotLog.d(TAG, "CheckNewMessageTimer, new message received but we're not scrolled to the bottom, turn the scroll button blue");
                            mFab.setBackgroundTintList(ColorStateList.valueOf(getResources().getColor(R.color.surespotBlue)));
                        }
                    }
                });
            }
        }

        private boolean newItemsAdded() {
            int dbLatestMessageID = mHomeViewModel.getMessageViewModel().getLatestMessageId(mOurUsername, mChatname);

            if (mLatestMessageId > 0 && dbLatestMessageID > mLatestMessageId) {
                mLatestMessageId = dbLatestMessageID;
                return true;
            }

            return false;
        }
    }

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