6

我已经在我的应用程序中集成了分页组件,它工作得非常好(几乎)。我有数据库+网络模型。数据库最初有一些项目被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使用 new 调用函数PagedList<Entity>。现在,这个分页列表是否只包含新项目。我已经证实了这一点。

但是onItemRangeInserted方法也是用positionStartas调用的0,这表明项目是在开头插入的。但他们不是。它们被插入到最后,由 stetho db 检查员确认。

那么为什么onItemRangeInserted被称为positionStartas0呢?这让我很难区分何时在适配器的开头插入新项目以及何时在末尾插入项目。

编辑:

的值为itemCount10,这是我的页面大小。

在 DiffCallback 中,我只是比较了函数中两个实体的主键列areItemsTheSame

4

1 回答 1

0

这就是我的做法,虽然不理想,但确实有效。我正在使用反向设置为 true 的回收器视图,因为它是一个聊天应用程序,因此您必须针对您的用例进行调整。

在您的片段中创建一个 Timer 字段:

private Timer mTimer;

添加一个滚动状态侦听器,该侦听器设置您稍后可以比较的“最新行 ID”。

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

    }
};

这是计时器类,如果已插入新项目,则“最新行 id”将在数据库中增加。如果我已经在底部,我只会滚动到底部,否则我只是更改我拥有的“滚动到底部”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;
        }
    }
于 2019-06-17T19:44:42.157 回答