web-dev-qa-db-fra.com

La bibliothèque de pagination renvoie initialement une liste vide

J'utilise la bibliothèque de pagination pour paginer une liste d'éléments que je récupère de mon serveur. Initialement, lorsque mon fragment est chargé, il renvoie une liste vide. Mais après avoir changé des fragments et revenir à ce fragment, je peux voir la liste chargée. Après le débogage, j'ai vu que les données étaient en train d'être récupérées, mais une liste vide a été transmise à mon fragment.

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

Fragment:

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

Pas sûr à 100%, mais je pense que c'est parce que vous exécutez une demande asynchrone. essayez de le changer pour qu'il fonctionne de manière synchrone pour loadInitial() comme ça request.execute()

8
Yassin Ajdi

J'ai également eu ce problème une fois et je n'arrive toujours pas à comprendre pourquoi cela ne fonctionne pas pour certains fragments. La solution que j'ai trouvée, qui ressemble plus à une solution rapide et sommaire, consiste à charger le fragment deux fois.

2
Edward Codarcea

Yassin Ajdi a raison. loadinitial() appelle immédiatement sur le même thread sur lequel PagedList est créé. Comme votre API est asynchrone, la méthode s'exécute vide pour la première fois

1
Alexander L.

Si, comme moi, quelqu'un utilise un appel asynchrone RxJava/Kotlin dans loadInitial. J'ai finalement trouvé une solution après de nombreuses heures douloureuses.

J'ai essayé d'utiliser un gestionnaire retardé (500 ms) dans la méthode Observer mais il était inconstant et ne fonctionnait pas dans tous les scénarios. Peu importe combien j'ai essayé de le rendre synchrone en utilisant setFetcher et Rx observeOn, cela ne fonctionnerait pas de manière cohérente.

Ma solution était d'utiliser .blockingSubscribe dans mon Observable. Mon récupérateur de données utilisait une bibliothèque Socket qui avait sa propre concurrence hors de ma portée, donc je ne pouvais pas garantir que je pouvais rendre le processus entièrement synchrone comme l'exige la pagination. (Un processus qui nécessite une meilleure documentation OMI). Quoi qu'il en soit, voici ma solution, j'espère qu'elle aidera d'autres personnes avec le même problème:

    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()
                })
    }
0
Conti