使用 Room 更新 PagingLibrary 中的列表项(仅限网络) [英] Update list items in PagingLibrary w/o using Room (Network only)
问题描述
我正在使用分页库从使用ItemKeyedDataSource
的网络加载数据.获取用户可以编辑的项目后,此更新在内存缓存中完成(不使用 Room 之类的数据库).
现在由于 PagedList
本身无法更新(讨论 here) 我必须重新创建 PagedList
并将其传递给 PagedListAdapter
.
更新本身没问题,但是在用新的PagedList
更新recyclerView
后,列表跳转到列表的开头,破坏了previous 滚动位置.无论如何要在保持滚动位置的同时更新 PagedList(例如它如何与 Room 一起使用)?
DataSource 是这样实现的:
public class MentionKeyedDataSource extends ItemKeyedDataSource{私有存储库;...私人名单<提及>缓存项;public MentionKeyedDataSource(Repository repository, ..., List cachedItems){极好的();this.repository = 存储库;this.teamId = teamId;this.inboxId = inboxId;this.filter = 过滤器;this.cachedItems = new ArrayList<>(cachedItems);}@覆盖public void loadInitial(@NonNull LoadInitialParams params, final @NonNull ItemKeyedDataSource.LoadInitialCallback 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));}@覆盖public void loadAfter(@NonNull LoadParams params, final @NonNull ItemKeyedDataSource.LoadCallback callback) {repository.getOlderItems(..., params.key, params.requestedLoadSize).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(response -> callback.onResult(response.data.list));}@覆盖public void loadBefore(@NonNull LoadParams params, final @NonNull ItemKeyedDataSource.LoadCallback callback) {repository.getNewerItems(..., params.key, params.requestedLoadSize).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(response -> callback.onResult(response.data.list));}@非空@覆盖public Long getKey(@NonNull 提及项) {返回 item.id;}}
PagedList 是这样创建的:
PagedList.Config config = new PagedList.Config.Builder().setPageSize(PAGE_SIZE).setInitialLoadSizeHint(preFetchedItems != null && !preFetchedItems.isEmpty()?preFetchedItems.size():PAGE_SIZE * 2).建造();pagedMentionsList = new PagedList.Builder<>(new MentionKeyedDataSource(mRepository, team.id, inbox.id, mCurrentFilter, preFetchedItems), 配置).setFetchExecutor(ApplicationThreadPool.getBackgroundThreadExecutor()).setNotifyExecutor(ApplicationThreadPool.getUIThreadExecutor()).建造();
PagedListAdapter 是这样创建的:
public class ItemAdapter extends PagedListAdapter- {//来自谷歌指南的适配器,这里没什么特别的.. }mAdapter = new ItemAdapter(new DiffUtil.ItemCallback
() {@覆盖公共布尔 areItemsTheSame(Item oldItem, Item newItem) {返回 oldItem.id == newItem.id;}@覆盖公共布尔 areContentsTheSame(Item oldItem, Item newItem) {返回 oldItem.equals(newItem);}});
,并更新如下:
mAdapter.submitList(pagedList);
P.S:如果有更好的方法可以在不使用 Room 的情况下更新列表项,请分享.
您需要做的就是在每次更新数据时使当前的 DataSource
失效.
我会做什么:
将网络逻辑从
MentionKeyedDataSource
移动到扩展PagedList.BoundaryCallback
的新类,并在构建PagedList
时设置它.p>将所有数据移动到某个
DataProvider
中,该DataProvider
包含所有下载的数据并引用DataSource
.每次在DataProvider
中更新数据都会使当前的DataSource
失效
应该是这样的
val dataProvider = PagedDataProvider()val dataSourceFactory = InMemoryDataSourceFactory(dataProvider = dataProvider)
哪里
class PagedDataProvider : DataProvider{private val dataCache = mutableMapOf>()覆盖 val sourceLiveData = MutableLiveData>()//在这里实现数据添加/删除/更新//并且在每次修改调用之后//sourceLiveData.value?.invalidate()}
和
class InMemoryDataSourceFactory(私有 val dataProvider: DataProvider) : DataSource.Factory() {override fun create(): DataSource{val source = InMemoryDataSource(dataProvider = dataProvider)dataProvider.sourceLiveData.postValue(source)返回源}}
这种方法与 Room
所做的非常相似 - 每次更新表行 - 当前 DataSource
无效并且 DataSourceFactory
创建新数据来源.
I'm using Paging Library to load data from network using ItemKeyedDataSource
. After fetching items user can edit them, this updates are done inside in Memory cache (no database like Room is used).
Now since the PagedList
itself cannot be updated (discussed here) I have to recreate PagedList
and pass it to the PagedListAdapter
.
The update itself is no problem but after updating the recyclerView
with the new PagedList
, the list jumps to the beginning of the list destroying previous scroll position. Is there anyway to update PagedList while keeping scroll position (like how it works with Room)?
DataSource is implemented this way:
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;
}
}
The PagedList created like this:
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();
The PagedListAdapter is created like this:
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);
}
});
, and updated like this:
mAdapter.submitList(pagedList);
P.S: If there is a better way to update list items without using Room please share.
All you need to do is to invalidate current DataSource
each time you update your data.
What I would do:
move networking logic from
MentionKeyedDataSource
to new class that extendsPagedList.BoundaryCallback
and set it when building yourPagedList
.move all you data to some
DataProvider
that holds all your downloaded data and has reference toDataSource
. Each time data is updated inDataProvider
invalidate currentDataSource
Something like that maybe
val dataProvider = PagedDataProvider()
val dataSourceFactory = InMemoryDataSourceFactory(dataProvider = dataProvider)
where
class PagedDataProvider : DataProvider<Int, DataRow> {
private val dataCache = mutableMapOf<Int, List<DataRow>>()
override val sourceLiveData = MutableLiveData<DataSource<Int, DataRow>>()
//implement data add/remove/update here
//and after each modification call
//sourceLiveData.value?.invalidate()
}
and
class InMemoryDataSourceFactory<Key, Value>(
private val dataProvider: DataProvider<Key, Value>
) : DataSource.Factory<Key, Value>() {
override fun create(): DataSource<Key, Value> {
val source = InMemoryDataSource(dataProvider = dataProvider)
dataProvider.sourceLiveData.postValue(source)
return source
}
}
This approach is very similar to what Room
does - every time table row is updated - current DataSource
is invalidated and DataSourceFactory
creates new data source.
这篇关于使用 Room 更新 PagingLibrary 中的列表项(仅限网络)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!