Kei*_*ati 8 android-adapter android-recyclerview android-architecture-components android-jetpack
我正在使用Paging Library使用来从网络加载数据ItemKeyedDataSource。提取项目后,用户可以对其进行编辑,此更新在内存缓存内部完成(不使用任何数据库,例如Room)。
现在,由于PagedList本身无法更新(在此处讨论),我必须重新创建PagedList并将其传递给PagedListAdapter。
更新本身没有问题,但是在recyclerView使用new 更新之后PagedList,列表会跳至列表的开头,从而破坏先前的滚动位置。无论如何,要在保持滚动位置的同时更新PagedList(例如它如何与Room一起工作)?
数据源是通过以下方式实现的:
public class MentionKeyedDataSource extends ItemKeyedDataSource<Long, Mention> {
private Repository repository;
...
private List<Mention> cachedItems;
public MentionKeyedDataSource(Repository repository, ..., List<Mention> cachedItems){
super();
this.repository = repository;
this.teamId = teamId;
this.inboxId = inboxId;
this.filter = filter;
this.cachedItems = new ArrayList<>(cachedItems);
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Long> params, final @NonNull ItemKeyedDataSource.LoadInitialCallback<Mention> callback) {
Observable.just(cachedItems)
.filter(() -> return cachedItems != null && !cachedItems.isEmpty())
.switchIfEmpty(repository.getItems(..., params.requestedLoadSize).map(...))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
@Override
public void loadAfter(@NonNull LoadParams<Long> params, final @NonNull ItemKeyedDataSource.LoadCallback<Mention> callback) {
repository.getOlderItems(..., params.key, params.requestedLoadSize)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
@Override
public void loadBefore(@NonNull LoadParams<Long> params, final @NonNull ItemKeyedDataSource.LoadCallback<Mention> callback) {
repository.getNewerItems(..., params.key, params.requestedLoadSize)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
@NonNull
@Override
public Long getKey(@NonNull Mention item) {
return item.id;
}
}
Run Code Online (Sandbox Code Playgroud)
该PagedList这样创建的:
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(PAGE_SIZE)
.setInitialLoadSizeHint(preFetchedItems != null && !preFetchedItems.isEmpty()
? preFetchedItems.size()
: PAGE_SIZE * 2
).build();
pagedMentionsList = new PagedList.Builder<>(new MentionKeyedDataSource(mRepository, team.id, inbox.id, mCurrentFilter, preFetchedItems)
, config)
.setFetchExecutor(ApplicationThreadPool.getBackgroundThreadExecutor())
.setNotifyExecutor(ApplicationThreadPool.getUIThreadExecutor())
.build();
Run Code Online (Sandbox Code Playgroud)
该PagedListAdapter创建这样的:
public class ItemAdapter extends PagedListAdapter<Item, ItemAdapter.ItemHolder> { //Adapter from google guide, Nothing special here.. }
mAdapter = new ItemAdapter(new DiffUtil.ItemCallback<Mention>() {
@Override
public boolean areItemsTheSame(Item oldItem, Item newItem) {
return oldItem.id == newItem.id;
}
@Override
public boolean areContentsTheSame(Item oldItem, Item newItem) {
return oldItem.equals(newItem);
}
});
Run Code Online (Sandbox Code Playgroud)
,并像这样更新:
mAdapter.submitList(pagedList);
Run Code Online (Sandbox Code Playgroud)
小智 8
您应该对可观察对象使用阻塞调用。如果你没有在同一个线程提交的结果loadInitial,loadAfter或者loadBefore,什么情况是,该适配器将计算diff对空列表现有的列表项,然后再对新加载项。如此有效,就好像所有项目都被删除然后再次插入一样,这就是列表似乎跳到开头的原因。
您没有androidx.paging.ItemKeyedDataSource.LoadInitialParams#requestedInitialKey在 的实现中使用loadInitial,我认为您应该这样做。
我查看了 的另一种实现ItemKeyedDataSource,即自动生成的 Room DAO 代码使用的实现:LimitOffsetDataSource。它的实现loadInitial包含(Apache 2.0许可代码如下):
// bound the size requested, based on known count
final int firstLoadPosition = computeInitialLoadPosition(params, totalCount);
final int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
...这些函数用params.requestedStartPosition,params.requestedLoadSize和做一些事情params.pageSize。
每当您传递 new 时PagedList,您需要确保它包含用户当前滚动到的元素。否则,您的 PagedListAdapter 会将其视为删除这些元素。然后,稍后,当您的 loadAfter 或 loadBefore 项加载这些元素时,它会将它们视为这些元素的后续插入。您需要避免删除和插入任何可见项目。由于听起来您正在滚动到顶部,因此也许您不小心删除了所有项目并将它们全部插入。
我认为将 Room 与 PagedLists 一起使用时的工作方式是:
loadInitial可见params.requestedStartPosition元素的集合。loadBefore或loadAfter。我不确定这与您想要做的事情有何对应,但这也许有帮助?每当您提供一个新的 PagedList 时,它将与前一个 PagedList 有所不同,并且您需要确保没有虚假的插入或删除,否则可能会变得非常混乱。
我还看到过 PAGE_SIZE 不够大的问题。文档建议一次可见的最大元素数的几倍。
| 归档时间: |
|
| 查看次数: |
3148 次 |
| 最近记录: |