0

I am trying to fetch a list of strings from API_1 (getList()), then iterate through each string in the list and make another API_2(syncData()) network call by each datatype string, somehow I don't understand why the code below can make second calls with forEach() but not flatMap().

flatMap() Version:

Observable.just(getListNetworkCall())
                .flatMapIterable(response -> response.getDataList())
                .flatMap(dataType -> syncData(dataType))
                .subscribeOn(Schedulers.io())
                .subscribe(new Consumer<Response2>() {
                    @Override
                    public void accept(Response2 response) throws Throwable {
                        System.out.println("response:" + response.toString());
                    }
                });

forEach() Version:

Observable.just(getList())
               .flatMapIterable(response -> response.getDataList())
               .forEach(dataType -> syncData(dataType));

private Observable<Response2> syncData(String dataType) {
        return Observable.just(syncDataNetworkCall(dataType));
}

What I saw in the flatMap() Version is that it did the getList() call only. Am I missing any piece of knowledge on RxJava, I also take reference on RxJava Combine Sequence Of Requests

Thanks.

  • One difference is that the *flatMap* method is using `Schedulers.io()` which can affect the order of execution. Try either adding `.subscribeOn(Schedulers.io())` to *forEach* method or removing scheduler from *flatMap* method and see if you can get the same behavior from both methods – Sanlok Lee Oct 04 '19 at 19:47
  • What is the execution order you mentioned affected by `flatMap()`, are you saying the emitting items(Response2) or something else? – Daayoung Code Oct 04 '19 at 20:38
  • I remove the `.subscribeOn(Schedulers.io())` from `flatMap() Version`, and it did perform the `syncData()` calls inside the _.flatmap_ operator. Can you explain why? Also I don't think I can add anything except `dispose()` after forEach() – Daayoung Code Oct 04 '19 at 20:42
  • `Schedulers.io()` will make the stream run on another thread. This means that the calling thread will not wait for `syncData(dataType)` call to complete. If you remove scheduler, it will run on the calling thread so the calling thread will wait until all `syncData` complete. If you want to add `.subscribeOn` in the *forEach* version, you can put it just before `.forEach` operator. In fact it doesn't really matter in which order you call `.subscribeOn` you can put it anywhere in the chain. – Sanlok Lee Oct 05 '19 at 03:37
  • 1
    That syncData method contains code executing right at the invocation inside `flatMap` and its result is wrapped into a `just` Observable. This is a common misunderstanding about Rx as `just` takes a constant reference and doesn't defer any calculation. – akarnokd Oct 05 '19 at 15:46
  • @SanlokLee Thank you for your answers. I also took a look `forEach()` https://github.com/ReactiveX/RxJava/wiki/Blocking-Observable-Operators so I understand why forEach works instead at the very first beginning. – Daayoung Code Oct 07 '19 at 18:51
  • @akarnokd Thank you for your answer and pointing out I have a misunderstanding on the Rx! – Daayoung Code Oct 07 '19 at 18:52

0 Answers0