Android分页边界回调澄清

Yas*_*svi 5 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;
            }
        });
Run Code Online (Sandbox Code Playgroud)

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);
                }
            }
        };
Run Code Online (Sandbox Code Playgroud)

我在这个模型中面临一个问题:

进行网络调用后,再次填充数据库并onChanged使用new调用函数PagedList<Entity>.现在,此分页列表是否仅包含新项目.我已经证实了这一点.

onItemRangeInserted方法被调用positionStart0过,这表明被插入在一开始的项目.但他们不是.它们被插入到最后,由stetho db检查员确认.

那么,为什么是onItemRangeInserted被调用positionStart0?这使我难以区分何时在适配器的开头插入新物品以及何时插入物品.

编辑:

value itemCount是10,这是我的页面大小.

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

2fo*_*urs 0

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

在您的片段中创建一个计时器字段:

private Timer mTimer;
Run Code Online (Sandbox Code Playgroud)

添加一个滚动状态监听器,设置一个“最新行 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));
                }
            }});
Run Code Online (Sandbox Code Playgroud)

当调用插入时,使用 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);

    }
};
Run Code Online (Sandbox Code Playgroud)

这是计时器类,如果插入了新项目,“最新行 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)