我已经在我的应用中集成了分页组件,它的工作非常好(几乎)。
我是数据库+网络模型。数据库最初有一些由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
?这使我很难区分何时在适配器的开头插入新物品以及何时插入物品。
编辑:
itemCount
的值是10,这是我的页面大小。
在DiffCallback中,我只是比较areItemsTheSame
函数中两个实体的主键列。
答案 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;
}
}