[英]Update list items in PagingLibrary w/o using Room (Network only)
I'm using Paging Library to load data from network using ItemKeyedDataSource
.我正在使用Paging Library使用
ItemKeyedDataSource
从网络加载数据。 After fetching items user can edit them, this updates are done inside in Memory cache (no database like Room is used).获取用户可以编辑的项目后,此更新在内存缓存中完成(不使用 Room 之类的数据库)。
Now since the PagedList
itself cannot be updated (discussed here ) I have to recreate PagedList
and pass it to the PagedListAdapter
.现在由于
PagedList
本身无法更新(在此处讨论),我必须重新创建PagedList
并将其传递给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.更新本身没有问题,但在使用新的
PagedList
更新recyclerView
后,列表跳转到列表的开头,破坏了以前的滚动位置。 Is there anyway to update PagedList while keeping scroll position (like how it works with Room )?无论如何要在保持滚动位置的同时更新 PagedList (就像它如何与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如下:
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: 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);
}
});
, and updated like this: ,并更新如下:
mAdapter.submitList(pagedList);
PS: If there is a better way to update list items without using Room please share. PS:如果有更好的方法可以在不使用 Room 的情况下更新列表项,请分享。
All you need to do is to invalidate current DataSource
each time you update your data.您需要做的就是在每次更新数据时使当前的
DataSource
无效。
What I would do:我会怎么做:
move networking logic from MentionKeyedDataSource
to new class that extends PagedList.BoundaryCallback
and set it when building your PagedList
.将网络逻辑从
MentionKeyedDataSource
移动到扩展PagedList.BoundaryCallback
新类,并在构建PagedList
时设置它。
move all you data to some DataProvider
that holds all your downloaded data and has reference to DataSource
.将所有数据移动到某个
DataProvider
,该DataProvider
包含所有下载的数据并引用DataSource
。 Each time data is updated in DataProvider
invalidate current DataSource
每次在
DataProvider
更新数据都会使当前的DataSource
失效
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
所做的非常相似 - 每次更新表行 - 当前DataSource
无效并且DataSourceFactory
创建新数据源。
You can modify directly in your adapter if you called currentList
like that如果您像这样调用
currentList
,则可以直接在适配器中进行修改
class ItemsAdapter(): PagedListAdapter<Item, ItemsAdapter.ViewHolder(ITEMS_COMPARATOR) {
...
fun changeItem(position: Int,newData:String) {
currentList?.get(position)?.data = newData
notifyItemChanged(position)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.