简体   繁体   English

使用 Room 更新 PagingLibrary 中的列表项(仅限网络)

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM