In his recent talk at DroidconSE, Matthias Käppler (Software Engineer at SoundCloud), proposed the use of RxJava in Android apps to elegantly handle asynchronous behaviour.
Traditionally Android developers have taken Google's lead and utilised the AsyncTask or Loader patterns for handling asynchronous behaviour. However, these approaches have a number of well publicised limitations, in particular:
- When declared as an inner classes of an Activity an AsyncTask will retain a reference to it, often leading to leaks of memory intensive Activity classes.
- As Activity instances are recreated after a device rotation, developers must program defensively when handling user interface updates in AsyncTasks.
- The only approach to orchestrating multiple AsyncTasks or Loaders is to use nesting, which leads to unwieldy code.
RxJava is an implementation of Reactive Extensions for the Java programming language. Netflix originally developed the library to address concurrency in the service tier of its video-on-demand applications. It was subsequently open-sourced in February 2013 and quickly adopted by pioneering Android developers. One such developer was Matthias, who has architected SoundCloud's Android application to utilise RxJava, and is now a key contributor to the RxAndroid project. After his talk InfoQ spoke to Matthias to discover how other Android developers can benefit from adopting RxJava.
InfoQ: Why should Android developers who are comfortable with AsyncTask or Loaders invest time in learning RxJava?
Matthias Käppler: We adopted RxJava because there are limitations to AsyncTask, Loaders, and Handler/Message which made them unsuitable for us as a means of transporting data in a resilient and reusable way. The primary reason is their lack of compositional APIs, which prevented us from expressing asynchronous operations as what they typically are: a sequence of steps where inputs and outputs are handed over from one step to the next. Closely related to this is the idea of performing such steps in a fault tolerant way, however, none of the above mentioned framework classes can express the fact that even an individual step failed, let alone an entire sequence. Since we frequently need to compose multiple data sources such as database and web API calls, and since furthermore mobile is an environment that is inherently prone to failure of many kinds (flaky networks, device fragmentation, etc.,) AsyncTask, Loaders, or Handler/Message alone can not be considered suitable tools. RxJava addresses this by providing a uniform way to describe a piece of work to be executed, how to transform or compose its result, all the while making sure that either result or failure end up safely at the subscriber, no matter if or where the sequence failed.
InfoQ: How has RxJava influenced and improved the architecture of the SoundCloud Android application?
MK: One major thing we struggled with in the past were the numerous ways Android offers the developer to let your objects communicate with each other. It's quite a zoo really: there are callbacks (often not consistently named or used), Handler/Message, Intents in various incarnations, ContentObservers, and so forth. By writing Rx adapters for these, we were able to streamline communication in the app and provide a uniform way to pass messages around, with all the benefits that RxJava gives you out of the box such as composability and error handling. One of the most widely used types in our app now is an event bus based on Rx Subjects, which allows us to let objects communicate in a decoupled fashion using the same Rx protocol all other observables use.
InfoQ: What were the biggest challenges you faced in adopting RxJava in the SoundCloud mobile application?
MK: The steep learning curve of adopting a functional programming style on top of Android's imperative framework classes, the unfamiliarity with implementation patterns and idioms in Rx, and the pre-release status of the library. We adopted RxJava at version 0.5, and had to deal with many breaking API changes on its way to the 1.0 stable release. It is crucial as well to get the entire team on board with the idea. Fortunately, this was not a big problem for us, as we all love to experiment and are willing to shift our view even radically, if necessary. In fact, our iOS team had adopted Rx through ReactiveCocoa well before the Android team did with RxJava, so there was a team wide shift to embrace the ideas behind Rx.
InfoQ: What are the implications on testing when adopting RxJava? Is it still possible to unit test reactive code?
MK: The short answer is: Absolutely. The long answer is: There was an initial learning curve here around how you define your interfaces, where you expose observable sequences and where you don't, what you should mock in tests and what you shouldn't mock. I only recently started to grasp this better myself. If you begin to understand observable sequences for their true nature, that is, as value streams, and not as traditional job objects like AsyncTask, then if you design your code in a way where you can plug these sequences in and out and are able to observe the result of a subscription directly or indirectly on the public API of the test subject, then it makes your code very testable. Another benefit is that since concurrency is parametric, i.e. can be swapped in and out of a sequence by means of Rx Schedulers, you can simply remove concurrency entirely from the equation in unit tests without changing the behavior of the class under test. Moreover, with TestScheduler you can manipulate the flow of time in unit tests. This is a powerful idea.
InfoQ: As a key contributor to the RxJava Android sub-project (RxAndroid), can you comment on what upcoming changes developers can look forward to? In particular are there any plans to develop UI bindings?
MK: Yes absolutely. This is a work in progress, but more and more developers have joined in and made contributions to the library, especially around the idea of binding view properties to observable sequences, and by expanding on the existing APIs that can adapt Android framework classes to be used as observables. There is also talk about providing a more holistic solution for app developers around RxAndroid (itself being a bare bones, no frills library) where pre-made framework components would be made available that can remove some of the boilerplate around binding asynchronous sequences to the Android Activity life-cycle. This is still in very early stages though, so I can't provide too much information around it at this point in time.
InfoQ: What resources would you recommend for Android developers wanting to begin adopting RxJava in their applications?
MK: I highly recommend reading "Introduction to Rx" by Lee Campbell [1] which is available as a Kindle eBook free of charge, since it sheds light on why the library was initially conceived and goes on to explain its key concepts based on real world use cases. It's based around the original Rx library for .NET and C#, but the ideas remain the same across platforms. Daniel Lew has started writing a series of Android specific blog posts about RxJava which I find very approachable as well [2]. Other than that, we're still in the process of getting the RxAndroid project [3] in shape with regards to code samples, as it has only recently been separated from the main library, so stay tuned! Last but not least, if you happen to catch Erik Meijer speaking about Rx, it'll be both eye opening and hilarious. He will teach you why engineers with pencils are not to be trusted.
The Reactive Manifesto outlines the core principles of the reactive architecture Matthias described. These principles were the focus of the Reactive Service Architecture track at this year's QCon San Francisco, as part of which Ben Christensen, a fellow contributor to the RxJava project, presented a talk on Reactive Programming with RxJava.