Правильно ли я использую flatMap для объединения результатов нескольких вызовов API?

Я хочу сделать несколько вызовов API (с тремя различными запросами) и объединить результаты, а затем отобразить их в onNext(), Это работает, но я обеспокоен тем, что flatMap не идеально подходит для этого.

@GET("www.examle.com/api/data/")
Observable<WebResultsResponse> getWebResults(@Query("param1") String query);

-----

private List<WebResult> resultsList;

private void requestWebResults(String query) {
    resultsList.clear();

    final Observable<List<WebResult>> observable = MainApplication.apiProvider.getApiProviderA.getWebResults("query1")
            .subscribeOn(Schedulers.io())
            .flatMap(new Function<WebResultsResponse, ObservableSource<List<WebResult>>>() {
                @Override
                public ObservableSource<List<WebResult>> apply(WebResultsResponse response) throws Exception {
                    if(response.getData() != null && response.getData().getResults() != null)
                        resultsList.addAll(response.getData().getResults());

                    return MainApplication.apiProvider.getApiProviderA.getWebResults("query2")
                            .flatMap(new Function<WebResultsResponse, ObservableSource<List<WebResult>>>() {
                                @Override
                                public ObservableSource<List<WebResult>> apply(WebResultsResponse response) throws Exception {
                                    if(response.getData() != null && response.getData().getResults() != null)
                                        resultsList.addAll(response.getData().getResults());

                                    return MainApplication.apiProvider.getApiProviderA.getWebResults("query3")
                                            .flatMap(new Function<WebResultsResponse, ObservableSource<List<WebResult>>>() {
                                                @Override
                                                public ObservableSource<List<WebResult>> apply(WebResultsResponse response) throws Exception {
                                                    if(response.getData() != null && response.getData().getResults() != null)
                                                        resultsList.addAll(response.getData().getResults());

                                                    return Observable.just(resultsList);
                                                }
                                            });
                                }
                            });
                }
            })
            .observeOn(AndroidSchedulers.mainThread());


    observer = new DisposableObserver<List<WebResult>>() {
        @Override
        public void onNext(List<WebResult> results) {
            // do something with results
        }

        @Override
        public void onError(Throwable e) {
        }

        @Override
        public void onComplete() {
        }
    };

    observable.subscribe(observer);
}

Это правильное использование flatMap()? Могу ли я как-нибудь передать resultsList вниз по цепочке вместо того, чтобы объявить его в качестве глобальной переменной?

2 ответа

Решение

Вы можете просто объединить их, если вам все равно, кто из них вернется первым

Observable<List<WebResult>> observable = MainApplication.apiProvider.getApiProviderA.getWebResults("query1")
                .mergeWith(MainApplication.apiProvider.getApiProviderA.getWebResults("query2"))
                .mergeWith(MainApplication.apiProvider.getApiProviderA.getWebResults("query3"))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

в onNext() вы получите каждый результат в виде отдельного списка, если вы хотите получить результат, когда все они сделаны со всеми результатами, которые вы можете использовать

Observable<List<WebResult>> observable = Observable.zip(MainApplication.apiProvider.getApiProviderA.getWebResults("query1"), MainApplication.apiProvider.getApiProviderA.getWebResults("query2"), MainApplication.apiProvider.getApiProviderA.getWebResults("query3"), (webResults, webResults2, webResults3) -> {
            List<WebResult> allResults = new ArrayList<>();
            allResults.addAll(webResults);
            allResults.addAll(webResults2);
            allResults.addAll(webResults3);
            return allResults;
        });

И в onNext() вы получите одну эмиссию со всеми результатами, сложенными вместе

С помощью ответа elmorabea я придумал это решение, используя zip:

List<Observable<WebResultsResponse>> results = new ArrayList<>();
results.add(MainApplication.apiProvider.getApiProviderA.getWebResults("query1"));
results.add(MainApplication.apiProvider.getApiProviderA.getWebResults("query2"));
results.add(MainApplication.apiProvider.getApiProviderA.getWebResults("query3"));

Observable<List<WebResult>> observable = Observable.zip(results, new Function<Object[], List<WebResult>>() {
    @Override
    public List<WebResult> apply(Object[] responses) throws Exception {
        List<WebResult> allResults = new ArrayList<>();
        for(int i=0; i<responses.length; i++) {
            WebResultsResponse response = (WebResultsResponse)responses[i];
            if(response != null && response.getData() != null && response.getData().getResults() != null)
                allResults.addAll(response.getData().getResults());
        }
        return allResults;
    }
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io());
Другие вопросы по тегам