Dans mon application Android, je souhaite effectuer plusieurs requêtes http à l'aide de retrofit et de rxjava pour récupérer des données json. Le nombre de requêtes dépend des préférences de l'utilisateur (de 1 à 40). Chaque requête est indépendante et renvoie le même type. J'ai donc essayé d'appliquer la manière recommandée dans cette question (Comment faire plusieurs requêtes et attendre que les données proviennent de toutes les requêtes de retrofit 2.0 - android) qui utilise la fonction zip de rx-java. Mais je n'ai pas pu trouver un moyen d'obtenir et de combiner les résultats de chaque demande. Le type de réponse que j'ai utilisé pour une seule demande de mise à niveau était Response<List<NewsItem>> où NewsItem est mon objet personnalisé. (la réponse est en fait un tableau json, mais en une seule demande, la mise à niveau le gère automatiquement et le convertit en liste de mon objet personnalisé) Ce que j'ai essayé jusqu'à présent est ci-dessous:

Mon interface API

public interface API {

    String BASE_URL = "xxx/";

    @GET("news/{source}")
    Observable<List<NewsItem>> getNews(@Path("source") String source);
}

Classe Viewmodel pour récupérer des données

public class NewsVM extends AndroidViewModel {

    public NewsVM(Application application){
        super(application);
    }

    private MutableLiveData<List<NewsItem>> newsLiveData;

    public LiveData<List<NewsItem>> getNewsLiveData(ArrayList<String> mySourceList) {

        newsLiveData = new MutableLiveData<>();
        loadNews(mySourceList);

        return newsLiveData;
    }

    private void loadNews(ArrayList<String> mySourceList) {

        Gson gson = new GsonBuilder().setLenient().create();

        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(API.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();

        API api = retrofit.create(API.class);

        //Gathering the requests into list of observables
        List<Observable<?>> requests = new ArrayList<>();
        for(String source: mySourceList){
            requests.add(api.getNews(source));
        }

        // Zip all requests
        Observable.zip(requests, new Function<Object[], List<NewsItem>>() {
            @Override
            public List<NewsItem> apply(Object[] objects) throws Exception {

                // I am not sure about the parameters and return type in here, probably wrong 
                return new ArrayList<>();
            }
        })
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.newThread())
            .subscribe(
                new Consumer<List<NewsItem>>() {
                    @Override
                    public void accept(List<NewsItem> newsList) throws Exception {

                        Log.d("ONRESPONSE",newsList.toString());
                        newsLiveData.setValue(newsList);
                    }
                },
                new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable e) throws Exception {

                        Log.d("ONFAILURE", e.getMessage());
                    }
                }
        ).dispose();

    }
}

Cela ne donne pas d'erreur mais ne donne pas de réponse car je ne pouvais pas gérer la réponse. Quelqu'un peut-il m'aider à combiner les résultats de chaque demande? J'ai cherché toutes les questions mais je ne trouve pas d'exemple comme celui-ci.

1
Huseyin Sahin 27 janv. 2019 à 22:41

3 réponses

Meilleure réponse

Essayez d'utiliser Observable.from(Iterable<? extends T> iterable) (Observable.fromArray() dans rx-java2) au lieu de zip Vous aurez donc quelque chose comme:

Observable.from(mySourceList)
    .flatMap(new Func1<String, Observable<List<NewsItem>>>() {
        @Override
           public Observable<List<NewsItem>> call(String source) {
                return api.getNews(source);
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.newThread())
        .toList() // This will give you List<List<NewsItem>>
        .map(new Func1<List<List<NewsItem>>, List<NewsItem>>() {
            @Override
            public List<NewsItem> call(List<List<NewsItem>> listOfList) {
                //Merged list of lists to single list using Guava Library
                List<NewsItem> list = Lists.newArrayList(Iterables.concat(listOfList));
                return list;
            }
        })
        .subscribe(new Subscriber<List<NewsItem>>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onNext(List<NewsItem> newsList) {
                //Attached the final newslist to livedata
                newsLiveData.setValue(newsList);
            }
        });

EDITED a mis à jour la méthode

1
Huseyin Sahin 31 janv. 2019 à 15:37

Object[] objects est le tableau des éléments renvoyés par les requêtes. En supposant que chacune de vos requêtes renvoie un List<NewsItem> et que vous vouliez combiner tous les NewsItem en un seul List<NewsItem>, je pense que vous pouvez faire quelque chose du genre:

private void loadNews(ArrayList<String> mySourceList) {
    ...
    // Zip all requests
    Observable.zip(requests, new Function<Object[], List<NewsItem>>() {
        @Override
        public List<NewsItem> apply(Object[] objects) throws Exception {
            List<NewsItem> combinedNewsItems = new ArrayList<>();
            for (Object response : objects) {
                combinedNewsItems.addAll((List<NewsItem>) response);
            }
            return combinedNewsItems;
        }
    })
        .subscribeOn(Schedulers.io())
        ...
}

Soyez conscient du type de casting.

0
Sanlok Lee 28 janv. 2019 à 05:04

Si le type de données que vous obtenez est le même Liste et que les demandes sont multiples, vous pouvez utiliser la méthode de récursivité pour créer 1 à n requêtes et ajoutez des données List sur chaque succès.

0
DeePanShu 28 janv. 2019 à 05:18