Обновление элементов списка в PagingLibrary без использования Room (только сеть) - PullRequest
0 голосов
/ 24 июня 2018

Я использую Библиотека подкачки для загрузки данных из сети, используя ItemKeyedDataSource. После извлечения элементов пользователь может их редактировать, эти обновления выполняются внутри кеша Memory (база данных, такая как Room, не используется).

Теперь, так как само PagedList не может быть обновлено (обсуждается здесь ), я должен воссоздать PagedList и передать его в PagedListAdapter.

Само обновление не проблема, но после обновления recyclerView новым 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;
    }
}

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);

P.S: Если есть лучший способ обновить элементы списка без использования Room, пожалуйста, поделитесь.

1 Ответ

0 голосов
/ 08 декабря 2018

Все, что вам нужно сделать, это аннулировать текущий DataSource каждый раз, когда вы обновляете свои данные.

Что я хотел бы сделать:

  • переместить сетевую логику из MentionKeyedDataSource в новый класс, который расширяет PagedList.BoundaryCallback и устанавливает его при построении PagedList.

  • переместите все ваши данные в какой-то DataProvider, который содержит все ваши загруженные данные и имеет ссылкудо DataSource.Каждый раз, когда данные обновляются в DataProvider аннулировать текущий 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 создает новый источник данных.

...