5
votes

I'm new to RxJava, often got confused by flatMap function. According to the doc, flatmap transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable

Can someone give a good use case for it? Why transform the original Observable into Observables (plural) then turn them into a single Observable.

Why don't you just use 'map'?

If you give an example in Android that's awesome, otherwise plain Java is good enough. Thanks

3

3 Answers

12
votes

Let's say you have an

Observable<Foo> fooObservable;

And you want to call another method which takes a Foo and emits an Observable<Bar>

Something like:

public Observable<Bar> getBars(Foo foo);

If you did:

fooObservable.map(foo -> getBars(foo));

You'd end up with an Observable<Observable<Bar>> because you've transformed your Foo -> Observable<Bar> which is probably not what you want.

Instead you can use flatMap which "flattens the observable":

Observable<Bar> barObservable = fooObservable.flatMap(foo -> getBars(foo));
28
votes

I see tag Android on your question. So, probably you should be familiar with Retrofit.

Let's image that you have 2 methods:

public interface FoxreyRestApi {

    @POST("/signin")
    Observable<SignInResponse> signin(@Body SignInRequest request);

    @GET("/user")
    Observable<User> getUser(String accessToken);
}

You want to get user data, but you need accessToken, which return is SignInResponse.

You can do this:

1). Create your RestAdapter.

2). Do queries one - after - another:

restAdapter.signin(request)
    .flatMap(r -> restAdapter.getUser(r.getAccessToken()))
    .subscribe(user -> {/*User your user*/});
2
votes

Very often I use it to transform some of the UI events to observable background tasks:

ViewObservable.clicks(calculateBtn)
    .flatMap(new Func1<OnClickEvent, Observable<Integer>>() {
      @Override
      public Observable<Integer> call(OnClickEvent onClickEvent) {
          return observeBackgroundOperation()
            .observeOn(AndroidSchedulers.mainThread())//interaction with UI must be performed on main thread
            .doOnError(new Action1<Throwable>() {//handle error before it will be suppressed
                @Override
                public void call(Throwable throwable) {
                    progress.setVisibility(View.GONE);
                    calculateBtn.setEnabled(true);
                    Toast.makeText(IOCombineSampleActivity.this, R.string.mix_error_message, Toast.LENGTH_SHORT).show();
                }
            })
            .onErrorResumeNext(Observable.<Integer>empty());//prevent observable from breaking
      }
    })
    .subscribe(new Action1<Integer>() {...});

Because it's easy to define background operations using observable, I used flatMap to transform button click events to 'something done in background events' (for example network request finished with Retrofit) and then observe them.

Note, that observable in flatMap can emit single value, which is done in sample.

This way I have declaratively defined interaction between UI and background processes. I handle errors with doOnError and then use onErrorResumeNext(Observable.<Integer>empty()) to prevent observable from terminating with onError. Because I use flatMap, my observable is not completed (while inner flatMap was) and is waiting for next click events.

Full sample of code you can find in my article.