Android分页边界回调澄清

时间:2018-05-08 10:45:37

标签: android android-recyclerview android-architecture-components android-jetpack android-paging

我已经在我的应用中集成了分页组件,它的工作非常好(几乎)。 我是数据库+网络模型。数据库最初有一些由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被调用positionStart0?这使我很难区分何时在适配器的开头插入新物品以及何时插入物品。

编辑:

itemCount的值是10,这是我的页面大小。

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

1 个答案:

答案 0 :(得分:0)

这就是我的操作方式,虽然不理想,但可以正常工作。我使用的是回收站视图,其中reverse设置为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;
        }
    }