I recently had the opportunity to rewrite one customer’s Android app. The solution were stuck up with components coupling, complicated thread synchronization and problematic callbacks system. The components were not testable, constraint to random coordination of used sub systems (bluetooth, network calls…). The best way to get back to a healthy solution was to recover its inner core business and extract from confusing technical code.
Let’s take a simple example, to illustrate how to write a reactive application. This article shows a way of rewriting a reactive Android API with RxJava/RxAndroid. It could be easily applied to any project that handle multiple flux of data. You will find references to other blogs, that helped me understand this kind of approach. Let’s go with the reactive weather app (sources available on github).
The weather app
The weather app is a simple app that asks for a location (red fab button) and gives back the weather for this location:
This app uses a SDK, which is in charge of downloading GPS coordinates of the location and the weather (WeatherSDK.java). Below the geocoding method (the other service of the SDK; getWeather, is quiet similar):
The callback is a simple interface to help handle response and error:
In the weather app side, displaying the weather is quiet complex with cascading callbacks (MainActivity.java):
The SDK has to handle the response in a background thread and give the hand back into the Android main thread. The thing is quiet tricky for remote API calls. Client integration can be quiet complex too (response handling, difficult reuse, errors catching…). Imagine it with complex business and subsystems call 😉
Making things observables with the Observable Pattern
In Java, we can very quickly fall into callback hell with anonymous classes, interfaces, etc… all of fairly heavy or verbose manner. Also Android imposes some rules (resource management, activity lifecycle and more…). The HandlerThread and Looper classes from Android are good to give the hand back for background stuff. But it’s doesn’t avoid you to build background multitask processing without the old java Thread stuff. Writing a multitasking system without a good abstraction layer is always a tedious challenge.
The first thing to do in this situation is to take a step back from this old imperative code, to see how to deal with Observables. Rather than directly calling a method, you define a mechanism for retrieving and transforming the data (the “Observable”) and then subscribe an “Observer” to it. The Observable will fires events with the Observer’s entry to capture and respond to its emissions whenever they are ready. A very good advantage of this approach is that, when you have a bunch of tasks that are not interdependent, you can start them all at the same time rather than waiting for each other to finish before starting. Another one is the ability to control the data flow between components: if your subscriber goes down, you won’t fire any notification.
The Observable pattern is the heart of RxJava framework:
Rx extends the Observer pattern to support sequences of data/events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety and concurrent data structures. RxJava
Let’s begin to unlock the Observables and reduce the complexity under the hood. The retrofit framework (updated to version 2.x) can directly handle Observable responses and help us considerably reduce our work (we add a new RxJavaCallAdapterFactory in MainModule.java):
Now, our network calls can handle directly Observables (WeatherWS.java):
In the end, our geocode method from the SDK is reduced to this (WeatherSDK.java):
The SDK code is greatly improve because we retrofit make the job for us: it encapsulates its responses as Observables.
Asynchronous & functional programming
There are many terms used to describe this model of asynchronous programming and design. Here we use the following Rx terminology: an Observer subscribes to an Observable. An Observable emits items or sends notifications to its Observers by calling the Observers’ methods. Now we can compose Observables, Observers and functional approach that deals with immutable sequence of data.
Let’s see the app with RxJava (MainActivity.java):
This code still looks complex (java verbosity), but we now have now the possibility to chain functions and think in terms of data stream: we firstly map a function to extract location from Geocode data (from first call). We then reuse the location to continue the stream to ask the its GPS coordinate (with a switchMap, help us to maintain the observable chain by reusing the result from first observable and chain it with a second observable). And then we subscribe on Observer to handle the final result of this stream (the weather itself).
Lambdas fit well with functional things, but are not available until Android 8 (Nougat). In Kotlin, you would have it in few lines 😉
It’s an important thing to be able to separate plumbing and business logic. It help make it more readable and easier to test and maintain. The first benefits that you can feel is the friendly callbacks that we can now provide. You can also make smarter things with error handling and avoid dirty try catch that don’t know what to do with.
You also gain access to smart multitasking facilities by assigning schedulers. You don’t have to bother about threading anymore: WeatherSDK.java defines a background thread and the callback thread with the subscribeOn and observeOn methods.
Behind the scenes: Reactive Streams
Elsewhere you will see that what we are calling “Observer” is sometimes called a “subscriber,” “watcher,” or “reactor.” In general we often refer to the same “reactor pattern”.
Asynchrony is needed in order to enable the parallel use of computing resources, on collaborating network hosts or multiple CPU cores within a single machine. http://www.reactive-streams.org
The big picture to keep in mind is that Reactive Streams represents a sequence of events (the stream), and two protagonists (Observable and an Observer to those events). Beware of not confusing with
java.util.Stream from Java 8, which is a collection wrapper to perform functions on it.
Sebastien Deleuze greatly explains what are reactive types:
Reactive types are not intended to allow you to process your requests or data faster, in fact they will introduce a small overhead compared to regular blocking processing. Their strength lies in their capacity to serve more request concurrently, and to handle operations with latency, such as requesting data from a remote server, more efficiently. They allow you to provide a better quality of service and a predictable capacity planning by dealing natively with time and latency without consuming more resources. Unlike traditional processing that blocks the current thread while waiting a result, a Reactive API that waits costs nothing, requests only the amount of data it is able to process and bring new capabilities since it deals with stream of data, not only with individual elements one by one.
The other great idea behind the specification is to define back pressure: a way to ensure a fast publisher doesn’t overflow a slow subscriber. Back pressure provides resilience by ensuring that all participants in a stream-based system participate in flow control to ensure steady state of operation and graceful degradation.
To continue the exploration of the reactive streams API, go with “A journey into reactive streams” from Kevin Webber. Also keep an eye on very good “notes on reactive programming” from Dave Syer. I also encourage you to read some of the articles about RxJava, from Dan Lew: “Grokking RxJava” series, “Error handling in RxJava” or “Don’t break the chain: use Rx compose operator“.
Your journey just begins
You won’t solve all your problem with a reactive approach. Sometimes AsyncTask or a good use of Handler will be just the right answer. RxJava fit well with Android, and is really smooth if you use Kotlin. We must think in terms of how data structures are composed rather than the sequence in which they execute, and we will clearly realize gains (performances, testability, robustness…). This is an entire mindset to build and a way to better see our software designs. Hope it help you have clearer ideas and let you to begin design reactive api 😉