RxJava — FlatMap vs. SwitchMap

Elizabeth Veprik
5 min readAug 10, 2018

--

FlatMap vs SwitchMap

Before we start

If you are an Android developer, there is high chance you’ve heard of RxJava or already published apps that uses it. It makes concurrency look easy, it simplifies Android application development.

If you don’t know about it yet, I highly recommend you to check out Realm Academy posts. This article is for someone who is already familiar with RxJava and its basics.

In this story

We will compare FlatMap and SwitchMap transformations, look at the diagrams and see how they are used in real application example. Lastly, I will show you how to write unit tests for them.

If you want to play with the full source code of the examples used here, check out this Github repository.

Alright, grab some ☕️ and let’s get started!

FlatMap vs. SwitchMap

FlatMap is popular transformation operation widely used by developers using Rx. Put it simply, it will turn items emitted by an observable into observables themselves, then merge emissions of those observables into one observable that emits all the items in no particular order. Resulting stream of events will contain items corresponding to all the emissions from the original observable and some of them may interleave. See the diagram below.

FlatMap: no order

For some use cases it is perfectly fine, but there are situations where you may want more efficient flow and preserve the order of emitted items.

SwitchMap is another Rx transformation operation that is different to FlatMap in that it will unsubscribe from previous observable after emitting new one ensuring that only items from most recently emitting observable are emitted. Following diagram should explain this.

SwitchMap: dispose previous observable

If you want to see more detailed diagram, check this one.

Real example

Looking at the official documentation it is kind of clear what is the difference between the two. What is not very clear though, is the real life use case when one is preferred over another.

Here I tried to come up with good example demonstrating how SwitchMap solves the problem that the FlatMap can not.

The example is simple application consisting of an ImageView and several buttons. Each button has a fruit name on it. Clicking any of the buttons will fetch an image with corresponding fruit from an image repository and update the ImageView. For the sake of example, image repository is configured to return an apple image within three seconds and others will be fetched instantly.

Using FlatMap

First, let’s look at the implementation with FlatMap. The view model will listen to click events and use FlatMap to map the clicked button ids to the images from the image repository:

The animation below demonstrates what happens when all three buttons are clicked in a sequence.

FlatMap

When user clicks Apple, Banana, and Orange buttons sequentially the Orange image should be the one that stays rendered. As you can see, this is not the case and the Apple appears sometime later.

What’s happening? The problem here is that FlatMap doesn’t cancel previous observable when new item is received and turned to an observable. So the request for the Apple image is not cancelled when user clicks the Banana button. By the nature of FlatMap, every click event will produce an image and the view model will render it. Since the Apple image takes longer to fetch, it is emitted the last and overrides the Orange image.

FlatMap doesn’t cancel previous observable

Using SwitchMap 🎉

To solve the issue with the Apple image we replace FlatMap with the SwitchMap.

As it was mentioned in the beginning of the article, SwitchMap is called “switch” because it acts like one: it will unsubscribe from previous observable every time it gets a new item that needs to be mapped, completely switching from one item to another. In our example it will guarantee, that the request for the Apple image is cancelled prior to handling the Banana image.

SwitchMap

As you can see, the Apple image is not displayed anymore. Following digram shows the events timeline.

SwitchMap cancels previous observable

Once Banana button is clicked, the Apple observable (requesting an apple image) is canceled immediately.

I deliberately made my example such that it is obvious when FlatMap produces undesirable side effect. But it is not always evident from the behaviour if the code runs as intended. Imagine the code that wrongfully uses FlatMap for network requests or asynchronous CPU intensive computations. This will at best waste precious user’s resources like battery and network, and at worst may lead to random bugs that are hard to reproduce.

Conclusion

If you don’t care about order of emitted items and absolutely need all of them to be emitted — use FlatMap.

If you are in the situation when every subsequent event is somewhat a replacement for the previous one — use SwitchMap.

Oh wait, how about Unit Testing?

We don’t need to write unit tests for RxJava operators themself(They are maintained by smart engineers and have unit tests).
But, we may want to write some unit tests for view model that uses them to guarantee that it will emit correct items. It will save you from trouble later, when new developer will naively change the operator in the method.

See the unit tests in this file on git repository, it emits only Second_Bitmap. There is another unit test for FlatMap that emits both First_Bitmap and Second_Bitmap

Food for thoughts

Could we use ConcatMap? What’s going to happen if we use ConcatMap?
How about ConcatMapEager? Check operators documentation site and find out :)

--

--