Introduction
If you’re an Android Developer you have most likely heard about RxJava and preferably plan on learning it (Lately I worked as a contractor for a big company where the android team has not heard of it yet, sigh). RxJava is the library when it comes to asynchronous and reactive programming. Before the typical way to do Async work was using Androids AsyncTask, Threading and a mix of Loopers, Handlers and Messages.
This usually not only endet up with a lot of boilerplate code (hello callback hell), but it was very easy to screw up and hard to debug.
We can use RxJava instead all of these things, enabling us to do complex stuff with a few lines of code.
There’s a famous quote of the founder C++, Bjarne Stroustrup,
„In C++ it’s harder to shoot yourself in the foot, but when you do, you blow off your whole leg.“
I guess this applies also to RxJava with its high amount of operators (see http://reactivex.io/documentation/operators.html for reference).
This Article is not about the basics of RxJava, I recommend you to go to vogella (https://www.vogella.com/tutorials/RxJava/article.html) if you’re not familiar with Rx at all yet.
As the title says this article is about the operators flatMap and map.
Scenario
For the purpose of demonstration let’s say we’re doing an API call and want to deserialize the JSON (you should not do this manually, there are libraries like GSON for this).
We’re calling a getUser (e.g. „/user/1“ where 1 Is the id) endpoint and receive a JSON which allows us to construct an instance of User
Map
The Map operator gives you the emitted data and allows you to apply changes to it. The resulted changes are being emitted then again.
userService.fetchUserJson(id=1).map { resultJson ->
this.userMapper.mapFromJson(resultJson) // the returned object here would be the user
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe ( {
// on success
view.displayUser(it)
},
{
// on failure
view.displayError()
})
What happens here is we’re doing the API call through fetchUserJsonId(id=1). Once the call is done we’re calling the map function which maps the resulted JSON to a User object and then emits that user object further down the data stream.
For the purpose of demonstration let’s say we’re doing an API call and want to deserialize the JSON (you should not do this manually, there are libraries like GSON for this).
flatMap
The FlatMap operator works almost the same as the map operator and can fulfill the same operations as the map operator.
Within the operator you receive the emitted data to which you can apply changes. However, this time the resulted data is not emitted directly but an observable of it is. In our scenario flatMap would return an object of type Observable<User> unlike only User, as in map.
This does not happen by magic, the specified return type of flatMap is a SingleSource. The compiler will force you to return a single
userService.fetchUserJson(id=1).flatMap { resultJson ->
Single.just(this.userMapper.mapFromJson(resultJson)) /* We’re forced to return a Single here. Returning just the user would give us a compilation error */
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe ( {
// on success
view.displayUser(it)
},
{
// on failure
view.displayError()
})
Now if would we have an observable that is constantly emitting items (e.g. a MessageObservable for a chatting app) then flatMap would be emitting for every received item another observable, which you could subscribe to again and do another heavy task (like another http request).
Due to its asynchronous nature it is not guaranteed that all the received objects of a flatMap operator get emitted within the same order again (You have concatMap for this, however this is out of the scope of this article).
When to use flatMap and when to use map
What are the main differences between map and flatMap ? Let’s say our observable is emitting an object Tuna.
The operator map emits an object of Tuna while flatMap emits an Observable of Tuna (Single<Tuna> to be specific).
While map blocks the stream until the mapping operation is done, flatMap transforms the returning object into an Observable and grants us therefore another potential async operation. Because of the 2nd async task in flatMap, we’re not guaranteed that the items that were received by the observable are also emitted within the same order. If we were using our heavy calls inside map, then the map method would have to be executed synchroniously and block meanwhile other items that were emitted and want to go further down the steam.
This gives us a clue when to use which:
- Whenever you want to do an offline operation (e.g. map an object Tuna to an object Bacon, verify data offline, check some fields) then you should use map
- Whenever you need to do another async call (e.g. http request) and need your data to be updated instantly then use flatMap()
I hope I could put some light over this topic for you. If you have any questions feel free to use the comment section.
PS: You might have noticed that I used Kotlin in this language. Kotlin is an amazing language crafted by JetBrains. You should definitely check it out if you have the time as it is slowly but surely becoming the new standard of android development. With its language tools you save a lot of boilerplate code and thanks to functional programming you’ll have new elegant ways to write your code. I can highly recommend this book if you want to learn Kotlin or read about it. What’s your opinion about the new rising giant?