Reputation: 7358
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
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
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
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