EyeQ Tech
EyeQ Tech

Reputation: 7358

RxJava, good use case of flatmap

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

Upvotes: 5

Views: 4591

Answers (3)

marwinXXII
marwinXXII

Reputation: 1446

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.

Upvotes: 2

Aleksandr
Aleksandr

Reputation: 4936

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

Upvotes: 28

Will
Will

Reputation: 6711

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

Upvotes: 13

Related Questions