Разъяснение границы обратного вызова для Android - PullRequest
0 голосов
/ 08 мая 2018

Я включил компонент пагинации в свое приложение, и он работает отлично (почти). У меня есть База данных + сеть модель. В базе данных изначально есть некоторые предметы, которые потребляются LivePagedListBuilder. Я наблюдаю это LiveData<PagedList<InboxEntity>> и в конечном итоге передаю список в PagedListAdapter#submitList(PagedList<T> pagedList), что-то вроде:

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 возвращает DataSource.Factory<Integer, Entity>.

Я прослушиваю граничный обратный вызов и инициирую сетевой вызов, когда он достигает конца списка с поисковым вызовом. Этот вызов снова заполняет базу данных.

Есть еще одна вещь. Я зарегистрировал AdapterDataObserver в представлении переработчика, потому что, если элемент был вставлен в начале, я должен прокрутить до верхней позиции:

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

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

У меня проблема с этой моделью:

После выполнения сетевого вызова база данных снова заполняется, и вызывается функция onChanged с новым PagedList<Entity>. Теперь, содержит ли этот постраничный список только новые элементы. Я подтвердил это.

Но метод onItemRangeInserted также вызывается с positionStart как 0, что предполагает вставку элементов в начале. Но это не так. Они вставляются в конце, подтверждено инспектором stetho db.

Тогда почему onItemRangeInserted вызывается с positionStart как 0? Это затрудняет мне различие, когда свежий элемент вставляется в начало адаптера, а когда элементы вставляются в конец.

Edit:

значение itemCount равно 10, что соответствует размеру моей страницы.

В DiffCallback я просто сравниваю столбец первичного ключа двух объектов в функции areItemsTheSame.

1 Ответ

0 голосов
/ 17 июня 2019

Вот как я это делаю, не идеально, но это работает. Я использую вид рециркулятора, для которого задано обратное значение true, поскольку это приложение для чата, поэтому вам придется настроить его в соответствии с вашим вариантом использования.

В вашем фрагменте создайте поле Timer:

private Timer mTimer;

Добавьте прослушиватель состояния прокрутки, который устанавливает «последний идентификатор строки», который вы можете сравнить позже.

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

Используйте AdapterDataObserver для запуска нового таймера при вызове вставки.

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

    }
};

Вот класс таймера, если новые элементы были вставлены, «последний идентификатор строки» будет увеличиваться в базе данных. Я прокручиваю только до дна, если я уже внизу, в противном случае я просто изменяю цвет FAB «прокрутка до дна», который у меня есть.

  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;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...