Библиотека пейджинга сначала возвращает пустой список

Я использую Paging library для разбивки списка элементов, которые я извлекаю с моего сервера. Первоначально, когда мой фрагмент загружен, он возвращает пустой список. Но после смены фрагментов и возврата к этому фрагменту я вижу, что список загружен. После отладки я увидел, что данные действительно были извлечены, но пустой список был передан моему фрагменту.

ItemDataSource:

@Override
public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, Item> callback) {
    apiService.getItems(OFFSET)
    .enqueue(new Callback<ItemWrapper>() {
        @Override
        public void onResponse(@NonNull Call<ItemWrapper> call,@NonNull Response<ItemWrapper> response) {
            callback.onResult(response.body().getItems(), null, OFFSET + 25);
        }

        @Override
        public void onFailure(@NonNull Call<ItemWrapper> call,@NonNull Throwable t) {
            t.printStackTrace();
        }
    });
}

@Override
public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Item> callback) {

}

@Override
public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Item> callback) {
    apiService.getItems(params.key)
            .enqueue(new Callback<ItemWrapper>() {
                @Override
                public void onResponse(@NonNull Call<ItemWrapper> call,@NonNull Response<ItemWrapper> response) {
                    Integer key = response.body().getItems().isEmpty() ? null : params.key + 25;
                    callback.onResult(response.body().getItems(), key);
                }

                @Override
                public void onFailure(@NonNull Call<ItemWrapper> call,@NonNull Throwable t) {
                    t.printStackTrace();
                }
            });
}

ItemDataSourceFactory:

@Override
public DataSource create() {
    ItemDataSource itemDataSource = new ItemDataSource();
    itemLiveDataSource.postValue(itemDataSource);
    return itemDataSource;
}

public MutableLiveData<ItemDataSource> getItemLiveDataSource() {
    return itemLiveDataSource;
}

ItemViewModel:

private LiveData<ItemDataSource> liveDataSource;
private LiveData<PagedList<Item>> itemPagedList;

private ItemViewModel(Application application) {
    ItemDataSourceFactory factory = new ItemDataSourceFactory();
    liveDataSource = factory.getItemLiveDataSource();

    PagedList.Config config = (new PagedList.Config.Builder())
                .setEnablePlaceholders(false)
                .setPageSize(ItemDataSource.LIMIT).build();

    itemPagedList = (new LivePagedListBuilder(factory, config)).build();
}

public LiveData<PagedList<Item>> getItems() {
    return itemPagedList;
}

Фрагмент:

ItemViewModel itemViewModel = ViewModelProviders.of(this).get(ItemViewModel.class);
itemViewModel.getItems.observe(this, items -> {
    adapter.submitList(items);
})

Ответ 1

Не уверен на 100%, но я думаю, что это потому, что вы выполняете асинхронный запрос. попробуйте изменить его, чтобы он работал синхронно для loadInitial() как, например, request.execute()

Ответ 2

У меня тоже однажды была эта проблема, и я до сих пор не могу понять, почему она не работает для некоторых фрагментов. Решение, которое я нашел, хотя это скорее быстрое схематичное исправление, состоит в том, чтобы загрузить фрагмент дважды.

Ответ 3

Ясин Айди прав. loadinitial() сразу вызывает в том же потоке, где создается PagedList. Поскольку ваш API асинхронный, метод запускается пустым в первый раз

Ответ 4

Если, как и я, кто-то использует асинхронный вызов RxJava/Kotlin в loadInitial. Я наконец нашел решение после многих мучительных часов.

Я пытался использовать задержанный обработчик (500 мс) в методе Observer, но он был непостоянным и не работал в каждом сценарии. Независимо от того, сколько я пытался сделать его синхронным, используя setFetcher и Rx observeOn, оно не будет работать последовательно.

Моим решением было использовать .blockingSubscribe в моем Observable. Мой сборщик данных использовал библиотеку Socket, которая имела собственный параллелизм вне моей области, поэтому я не мог гарантировать, что смогу сделать процесс полностью синхронным, как того требует пейджинг. (Процесс, который требует лучшей документации IMO). В любом случае, вот мое решение, надеюсь, оно поможет другим с такой же проблемой:

    override fun loadInitial(
            params: LoadInitialParams<Int>,
            callback: LoadInitialCallback<Int, ResultItem>
    ) {
       mySocketClientRxRequest()
                .subscribe ({
                    callback.onResult(it.resultItems 1, 2)
                },{
                    it.printStackTrace()
                })
    }

в

    override fun loadInitial(
            params: LoadInitialParams<Int>,
            callback: LoadInitialCallback<Int, ResultItem>
    ) {
       mySocketClientRxRequest()
                .blockingSubscribe ({
                    callback.onResult(it.resultItems 1, 2)
                },{
                    it.printStackTrace()
                })
    }