不使用房间更新PagingLibrary中的列表项(仅网络) [英] Update list items in PagingLibrary w/o using Room (Network only)
问题描述
我正在使用分页库使用 ItemKeyedDataSource
从网络加载数据。提取项目后,用户可以对其进行编辑,此更新将在内存缓存中完成(不使用任何数据库,例如Room)。
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).
PagedList
本身无法更新(在 PagedList
并将其传递给 PagedListAdapter
。
Now since the PagedList
itself cannot be updated (discussed here) I have to recreate PagedList
and pass it to the PagedListAdapter
.
更新本身没有问题,但是在使用新的 PagedList
更新了 recyclerView
之后,列表会跳到列表的开头,从而破坏上一个滚动位置。是否有在保持滚动位置的同时更新PagedList的方法(例如它如何与 Room 一起使用)?
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 是这样实现:
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;
}
}
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();
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);
}
});
,并像这样更新:
mAdapter.submitList(pagedList);
PS:如果有更好的方法来更新列表项而不使用Room,请共享。
P.S: If there is a better way to update list items without using Room please share.
推荐答案
您需要做的就是每次更新您的当前 DataSource
均无效数据。
All you need to do is to invalidate current DataSource
each time you update your data.
我要做什么:
-
移动网络逻辑从
MentionKeyedDataSource
到扩展PagedList.BoundaryCallback
的新类,并在构建PagedList <时进行设置/ code>。
move networking logic from
MentionKeyedDataSource
to new class that extendsPagedList.BoundaryCallback
and set it when building yourPagedList
.
将所有数据移动到保存所有下载内容的 DataProvider
数据,并引用了 DataSource
。每次在 DataProvider
中更新数据时,都会使当前的 DataSource
move all you data to some DataProvider
that holds all your downloaded data and has reference to DataSource
. Each time data is updated in DataProvider
invalidate current DataSource
类似的东西
val dataProvider = PagedDataProvider()
val dataSourceFactory = InMemoryDataSourceFactory(dataProvider = dataProvider)
其中
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()
}
和
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
}
}
此方法与 Room
的操作非常相似-每次更新表行-当前 DataSource
无效,并且 DataSourceFactory
创建新的数据源。
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.
这篇关于不使用房间更新PagingLibrary中的列表项(仅网络)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!