Am I using flatMap correctly to merge results from multiple API calls?

点点圈 提交于 2021-01-28 08:19:04

问题


I want to make multiple API calls (with three different queries) and merge the results and then display them in onNext(). It is working but I am concerned that flatMap is not ideal for this.

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

Is this correct use of flatMap()? Can I somehow pass resultsList down the chain instead of having it declared as a global variable?


回答1:


You can simply merge them if you don't care which one is returns first

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

in onNext() you will get each result as it's own list, if you want to get the result when they are all done with all the results you can use

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

And in onNext() you will get one emission with all the results added together




回答2:


With the help of elmorabea's answer, I came up with this solution using 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());


来源:https://stackoverflow.com/questions/48240177/am-i-using-flatmap-correctly-to-merge-results-from-multiple-api-calls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!