0% found this document useful (0 votes)
153 views

Reactive Android

Reactive Android
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
153 views

Reactive Android

Reactive Android
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 108

Reactive Programming on Android with

RxJava
Christopher Arriola and Angus Huang
This book is for sale at http://leanpub.com/reactiveandroid

This version was published on 2017-06-27

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.

© 2017 Christopher Arriola and Angus Huang


This book is dedicated to my wife, Bianca. You inspire me beyond measure. - Chris Arriola
Contents

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Feedback and Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Part 1: RxJava Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2


Chapter 1: What is Reactive Programming? . . . . . . . . . . . . . . . . . . . . . . . . . . 3
The History of Reactive Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

Chapter 2: RxJava Core Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13


The 3 O’s: Observable, Observer, and Operator . . . . . . . . . . . . . . . . . . . . . . . 15
Marble Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Creating an Observable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Cold vs. Hot Observable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Lazy Emissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

Chapter 3: Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Transforming and Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Combining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Aggregating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Utility Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Reusing Operator Chains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

Chapter 4: Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Asynchronicity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Schedulers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Concurrency with FlatMap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

Part 2: RxJava Advanced . . . . . . . . . . . . . . . . . . . . . . . . . . . 57


Chapter 5: Reactive Modeling on Android . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Bridging Non-Reactive into the Reactive world . . . . . . . . . . . . . . . . . . . . . . . 58
Leaving the Reactive world . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
CONTENTS

The Lazy Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61


Reactive Everything . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Disposable and the Activity/Fragment Lifecycle . . . . . . . . . . . . . . . . . . . . . . . 75

Chapter 6: Backpressure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Fast Producer, Slow Consumer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Backpressure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Throttling and Buffering Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

Chapter 7: Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91


Errors Along the Chain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Delivering Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Error-Handling Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Retry Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Undelivered Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Introduction
Since its inception in 2012, RxJava has slowly gained in popularity for enabling reactive program-
ming on Android. Today in 2017, it is now deemed as the go-to and leading reactive library. Many
companies have adopted the reactive way of programming including Google with its release of
Android Architecture Components¹, which has many reactive elements in its design.
In Reactive Programming on Android with RxJava, we seek to condense RxJava principles and
provide a structured and simplified approach with a lot of code examples. This book seeks to serve
as a foundation for experienced Android developers who are new to RxJava so that they can start
integrating it into their apps.
The book is broken into two parts:
The 1st part of the book will go through the basics:

• In Chapter 1, we will give the backstory of RxJava and discuss what reactive programming is.
• In Chapter 2, we will examine the core components in RxJava.
• In Chapter 3, we will dive deeper into operators and highlight a couple of important ones.
• In Chapter 4, we will cover multithreading and concurrency.

The 2nd part of the book will go through advanced concepts:

• In Chapter 5, we will put together all the lessons from the 1st part of the book and see how
they apply to Android.
• In Chapter 6, we will talk about backpressure to control the flow of data.
• In Chapter 7, we will go over error handling and how it differs from Java’s exception handling.

Feedback and Questions


For any feedback or questions, please reach out to us directly:

• Christopher Arriola (Email: [email protected], Twitter: @arriolachris)


• Angus Huang (Email: [email protected])

¹https://developer.android.com/topic/libraries/architecture/index.html
Part 1: RxJava Basics
Chapter 1: What is Reactive
Programming?
Reactive programming can most simply be defined as asynchronous programming with observable
streams. Well, what does that mean? Let’s break it down…
Asynchronous programming, in the context of reactive programming, is a bit of a loaded term. In
the traditional sense, it is programming in a non-blocking way such that long-running tasks are
performed separately from the main application thread. In another sense, it is an event-driven style
of programming where the events themselves are asynchronous and can arrive at any point in time.
Observable refers to an entity that can be subscribed to by any number of observers interested in its
state. The observable entity will then push updates to its observers when there is a state change or
event arrival. This is the classic Observer Pattern.
A stream (or data stream) can be thought of as an ordered sequence of events. These events may
arrive at any point in time, may have no defined beginning or end, and are often generated by
sources external to our application.
Re-assembling these terms, an observable stream is, then, a sequence of events that can be subscribed
to and whose observers will be notified for each incoming event. And asynchronous programming
with observable streams is a way to asynchronously handle data streams by using a push-based,
observer pattern to keep the application responsive.
Can you think of some examples of data streams that we might want to handle using reactive
programming? As an Android developer, you have no doubt dealt with many forms of data streams…

• User-Generated Events: Click events, swipe events, keyboard input, device rotations… these
are just a few examples of events initiated by the user. If we consider each of these events
across a timeline, we can see how they would form an ordered sequence of events–a dynamic
and potentially infinite data stream.
• I/O Operations: Network requests, file reads and writes, database accesses… I/O operations
are probably the most common type of data streams you will apply reactive principles to
in practice. I/O operations are asynchronous since they take some significant and uncertain
amount of time to complete. The response–whether it be JSON, a byte array, or some plain-old
Java objects–can then be treated as a data stream.
• External System Events: Push notifications from the server, GCM broadcasts, updates from
device sensors… events generated from external producers are similar to user-generated events
in their dynamic and potentially infinite nature.
Chapter 1: What is Reactive Programming? 4

• Just About Anything: Really. Just about anything can be modeled as a data stream–that’s
the reactive mantra. A single, scalar value or a list of objects… static data or dynamic events…
any of these can be made into a data stream in the reactive world.

All of the previous examples are events that we want our program to take immediate action on. That
is the point of reactive programming–to be reactive. With reactive programming, data is a first-class
citizen. Your program will be driven by the flow of data as opposed to the thread of execution. And
RxJava, the library we will be using, provides a thorough set of APIs for dealing with these data
streams in a concise and elegant manner. But before we delve into the anatomy of RxJava, let’s take
a look at how it came to be.

The History of Reactive Programming


On October 28, 2005, Microsoft CTO, Ray Ozzie, wrote a 5000-word internal memo titled “The
Internet Services Disruption”. The memo stressed to every department at Microsoft that they needed
to adapt to the new Internet services era. With big players in the field like Google, Facebook, and
Amazon, they needed to move fast.
Erik Meijer and the Cloud Programmability Team at Microsoft heeded that call. They were
determined to alleviate the complexity that plagued these large systems and killed developer
productivity. The team decided to work on a programming model that could be utilized for these
data-intensive Internet services. The breakthrough occurred when they realized that by dualizing
the Iterable interface from the Gang of Four’s Iterator Pattern², they would have a nice push-based
model for easily dealing with asynchronous data streams. Over the course of the next couple years,
they would refine this idea and create Rx.NET (Reactive Extensions for .NET).
Rx.NET defined the set of interfaces (i.e. IObservable, IObserver) that would be fundamental to
reactive programming. Along with these came a toolbox of APIs for manipulating data streams such
as mapping, filtering, selecting, transforming, and combining. Data streams had achieved first-class
status with Rx.NET.

The Birth of RxJava


One of the first users of this technology was Jafar Husain. When he left Microsoft and joined Netflix
in 2011, he continued to evangelize Rx. Around that time, Netflix had successfully transitioned from
a DVD rental service to an on-demand, streaming service. By 2012, business was booming–they
would reach nearly 30 million subscribers by the end of the year. During this upward trajectory, the
Netflix team realized that their servers were having a hard time keeping up with the traffic.
The problem was not simply in the sheer number of streaming subscribers but also in the myriad
devices that Netflix supported. There were set-top boxes, smart TVs, game consoles, desktop
²https://en.wikipedia.org/wiki/Iterator_pattern
Chapter 1: What is Reactive Programming? 5

computers, and mobile devices. Each device had their own distinct UI/UX dictated by things like
screen size, network bandwidth, input controls, and platform requirements. Netflix, at the time, had
a generic, one-size-fits-all API for these clients to query. This meant that clients would often have to
issue multiple queries to get all the required data and then piece them together to fit their particular
UI. Not only would this be complex and slow on the client side, but it resulted in a lot of extra load
on the server. Ben Christensen and his team decided to overhaul the Netflix API server architecture
in order to decrease chattiness, increase performance, and allow for scalability.
They wanted their server API to be a “platform” for APIs and then hand over the reigns of
implementing those APIs to the client teams. By having each client team develop their own custom
endpoints, the clients could consolidate multiple calls into a single call and get the exact data they
needed. This eliminated not only the latency of multiple network calls on the client but also load on
the server.
The client teams were not expert server developers, however, and writing server APIs is not a trivial
exercise. Performant servers usually need to utilize multiple threads to service simultaneous requests
and issue concurrent requests to backend services and databases. The problem is… concurrent
programming is difficult. The server team needed to make the process as simple and error-proof
as possible for the client teams.
Luckily, Jafar Husain was there to preach the merits of Rx to Ben Christensen, who realized it was
a great approach to addressing all of the problems mentioned above. Among other things, reactive
programming abstracts threading away so that developers do not have to be experts in writing
concurrent programs.
Because the Netflix APIs were implemented in Java, they began to port the Reactive Extensions to
Java. They called it RxJava³ and–in Netflix-fashion–open-sourced it. They stayed as close to the
Rx.NET implementation as possible while adjusting naming conventions and idioms to suit the Java
programming language. In February 2013, Ben and Jafar announced RxJava to the world in a Netflix
Tech Blog post⁴.

Reactive on Android
Even though RxJava started with the Netflix servers, it found its way across the tech stack and across
the industry. From backends to frontends, web services to mobile clients… anything event-driven
was a good candidate to get a reactive makeover.
While making its way across the stack, Rx also made its way across programming languages.
Ports to other languages were worked on as open-source projects under an umbrella project called
ReactiveX⁵. Reactive extensions were implemented for just about all the popular programming
languages you could imagine: C++, Scala, Ruby, Python, Go, Groovy, Kotlin (go check out our other
³https://github.com/ReactiveX/RxJava
⁴https://medium.com/netflix-techblog/reactive-programming-in-the-netflix-api-with-rxjava-7811c3a1496a
⁵http://reactivex.io/
Chapter 1: What is Reactive Programming? 6

book⁶!), PHP, and Swift. There are even extensions for various frameworks, such as RxCocoa and
RxAndroid (the latter of which we will no doubt discuss in this book).
The event-driven nature of Android made it an ideal platform for reactive programming. Android
developers constantly have to deal with dynamic events in a responsive manner while making sure
not to block the UI thread. Existing constructs like AsyncTask are both verbose and inadequate. And
so RxJava’s popularity in the Android world is no fluke.

Reactive Manifesto
Another contributor to the bump in popularity for reactive programming was the Reactive
Manifesto. This was a document written by Jonas Bonér, Dave Farley, Roland Kuhn, and Martin
Thompson in 2013 (and updated in 2014). The manifesto argued that our present day’s demand
for increasing amounts of data and faster response times required a new software architecture–a
reactive one. They defined a Reactive System to be one that is Responsive, Resilient, Elastic, and
Message-Driven.
To date, nearly 20,000 people have signed the document. However, we leave the Reactive Manifesto
here as an aside in this book since it only looks at reactive programming from a 10,000-foot view
rather than really discussing how to accomplish it.
http://www.reactivemanifesto.org/

An Example
Let’s take a look at some RxJava in action:

1 Observable<Car> carsObservable = getBestSellingCarsObservable();


2
3 carsObservable.subscribeOn(Schedulers.io())
4 .filter(car -> car.type == Car.Type.ALL_ELECTRIC)
5 .filter(car -> car.price < 90000)
6 .map(car -> car.year + " " + car.make + " " + car.model)
7 .distinct()
8 .take(5)
9 .observeOn(AndroidSchedulers.mainThread())
10 .subscribe(this::updateUi);

The above code will get the top 5 sub-$90,000 electric cars and then update the UI with that data.
There’s a lot going on here, so let’s see how it does this line-by-line:
⁶https://leanpub.com/reactiveandroidrxkotlin
Chapter 1: What is Reactive Programming? 7

• Line 1: It all starts with our Observable, the source of our data. The Observable will wait
for an observer to subscribe to it, at which point it will do some work and push data to its
observer. We intentionally abstract away the creation of the carsObservable here, but we will
cover how to create an Observable in the next chapter. For now, let’s assume the work that
the Observable will be doing is querying a REST API to get an ordered list of the top-selling
cars.

Lines 3 - 10 form essentially a data pipeline. Items emitted by the Observable will travel through
the pipeline from top to bottom. Each of the functions in the pipeline are what we call an Operator;
Operators modify the Observable stream, allowing us to massage the data until we get what we
want. In our example, we start with an ordered list of all top selling car models. By the end of our
pipeline, we have just the top 5 selling electric cars that are under $90,000. The massaging of the
data happens as follows:

• Line 3: .subscribeOn(...) tells the Observable to do its work on a background thread. We


do this so that we don’t block Android’s main UI thread with the network request performed
by the Observable.
• Line 4: .filter(...) will filter the stream down to only items that represent electric cars.
Any Car object that does not meet this criteria will be discarded at this point and will not
continue down the stream.
• Line 5: .filter(...) will further filter the electric cars to those below $90,000.
• Line 6: .map(...) will transform the element from a Car object to a String consisting of the
year/model/make. From here on, this String will take the place of the Car in the stream.
• Line 7: .distinct() will remove any elements that we’ve already encountered before. Note,
that this uniqueness requirement applies to our String values and not our Car instances,
which no longer exist at this point in our chain because of the previous .map(...) call.
• Line 8: .take(5) will ensure that at most 5 elements will be passed on; if 5 elements are
emitted, the stream will complete and emit no more items.
• Line 9: .observeOn(...) switches our thread of execution back to the main UI thread. So
far, we’ve been working on the background thread specified in Line 3. Now that we need to
manipulate our Views, however, we need to be back on the UI thread.
• Line 10 .subscribe(...) is both the beginning and end of our data stream. It is the beginning
because .subscribe() prompts the Observer to do its work and start emitting items. However,
the parameter we pass to it is the Observer, which represents the end of the pipeline and
defines some action to perform when it receives an item (in our case, the action will be to
update the UI). The item received will be the result of all of the transformations performed by
the upstream Operators.

RxJava’s Essential Characteristics


Taking our example, let’s take a step back and examine the defining characteristics of RxJava.
Chapter 1: What is Reactive Programming? 8

Observer Pattern

RxJava is a classic example of the Observer Pattern. We start with the Observable, which is the
source of our data. Then we have one or more Observers, which subscribe to the Observable and
get notified when there is a new event. This allows for a push-based mechanism, which is usually far
more ideal than continually polling for new events. RxJava adds to the traditional Observer Pattern,
however, by also having the Observable signal completion and errors along with regular events,
which we will see in Chapter 2.

Iterator Pattern

With a traditional Iterator Pattern, the iterator pulls data from the underlying collection, which
would implement some sort of Iterable interface. What Erik Meijer essentially did in creating Rx
was flip the Iterator Pattern on its head, turning it into a push-based pattern.
The Observable was designed to be the dual of the Iterable. Instead of pulling data out of an
Iterable with .next(), the Observable pushes data to an Observer using .onNext(). So, where the
Iterator Pattern uses synchronous pulling of data, RxJava allows for asynchronous pushing of data,
allowing code to be truly reactive.

Functional Programming

One of the most important aspects of RxJava is that it uses functional programming, in particular,
with its Operators. Functional programming is programming with pure functions. A pure function
is one that satisfies the following two conditions:

1. The function always returns the same value given the same input (i.e. it’s deterministic).
This implies that the function cannot depend on any global state (e.g. a Java class’s member
variable) nor any external resource (e.g. a web service).
2. The function does not cause any side effects. This means that the function cannot mutate any
input parameter, update any global state, or interact with any external resource.

Functional programming leads to code that is…

• Declarative: Instead of dictating how something is done, as is done with imperative program-
ming, RxJava uses a declarative approach by describing what should be done (through our use
of Operators). This declarative style maps much more closely to how we as humans think (as
opposed to how a computer executes), and allows us to much more easily reason about what
the program is doing.
• Thread-Safe: Because functional programming avoids state mutation, it is inherently thread-
safe. We have none of the problems that we normally see when introducing concurrency (e.g.
synchronization issues, race conditions, resource contention). Concurrency can be supported
safely and easily with RxJava.
Chapter 1: What is Reactive Programming? 9

• Testable: Functional code becomes much easier to test because the functions are completely
self-contained and deterministic. We don’t need to mock the global state before executing unit
tests; all we need is a set of input and expected output.

Note that not all RxJava Operators are totally pure. Case in point are the “do” methods (e.g.
.doOnNext()), which were designed with the express purpose of letting the developer inject side
effects, such as logging to the console, in order to examine the data stream at any point in the
chain.

Note that no program can be functional forever. At some point, it needs to be imperative and spell
out to the computer exactly how to do something, and it needs to modify state (whether that is
updating a View, writing to the server, or just printing to console). RxJava just provides us a nice
abstraction over the imperative, allowing us to program functionally. The idea is to implement as
much of the program as you can using a functional approach and push out the imperative stuff to
the very furthest edges of the program where being imperative becomes unavoidable. With the bulk
of our program being functional, it will be more declarative, thread-safe, testable, and hopefully,
free of bugs.

Conciseness

For how much it’s doing, the code above is extremely concise. Imagine the number of lines that
would be required to write this without RxJava. Indeed, a huge reason why the code is so concise is
the use of lambdas. RxJava’s functional style and lambdas go hand in hand. We recommend you use
lambdas in your Java/Android project regardless, but especially so if you are using RxJava. If you
are not yet using Android Studio 3.+, we recommend using the Retrolambda⁷ library to add lambda
support to your project. RxJava really isn’t all that it can be without lambdas.
The second reason for its conciseness is the library of Operators that RxJava provides. These
Operators provide extremely helpful functions that would otherwise take many lines of code to
implement.
Thirdly, RxJava Operators are designed to be chained together, which also contributes to the
conciseness of the resulting code. Each Operator method itself returns a modified Observable
allowing for a subsequent Operator to be chained.
⁷https://github.com/evant/gradle-retrolambda
Chapter 1: What is Reactive Programming? 10

Fluent Interface

Although the above code snippet probably requires an initial somewhat-lengthy explanation, once
you have a baseline understanding, you can see the code is very idiomatic and self-explanatory.
RxJava uses a fluent interface with Operator names that read like English prose, especially when
chained together. This allows for not only faster coding, but also for someone reading the code to
parse what’s going on much more quickly.

Lazy Evaluation

RxJava, in general, uses lazy evaluation. Remember from above that the network call is not
performed until the very last step when we make the .subscribe() call. The Observable lays idle
until an Observer subscribes to it. Because subscription initiates the action, the Observable can be
reused; every Observer that subscribes will cause the Observable to be invoked.
Lazy evaluation has its pros and cons. In many cases, lazy evaluation is beneficial. For example, if
the Observable queries a web service, we likely want the most up-to-date data, which means that
execution should happen when the Observer subscribes (and not when the Observable is created).
The same should apply for any Observer that subscribes to the Observable; no matter what time
the Observer subscribes, it should get the latest data.
However, if our Observable is retrieving data that will not change, then we do not want it to make
a network round-trip for every subscriber. We’d prefer eager evaluation in this case and have the
Observable get the data once and hold on to it. RxJava, and its plentiful toolbox of APIs, actually
allows for this with the .cache() operator. In fact, we’ll see how to dictate the laziness vs. eagerness
of an Observable more when we talk about Observable creation and cold vs. hot Observables in
Chapter 2.

Easy Concurrency

In our example, we were able to have the network request executed on a background thread and
then switch back to having the UI be updated on the main UI thread. This was accomplished with
literally two lines of code (using our .subscribeOn() and .observeOn() Operators). We didn’t
have to manually create a new Thread; we didn’t have to implement an AsyncTask class and all its
methods; we didn’t have to lock or synchronize anything. This is concurrency made easy. We will
take a deeper dive into concurrency in Chapter 4: Multithreading.

Async Error Handling

Java’s regular error-handling mechanism of throwing/catching exceptions is ill-equipped at han-


dling concurrency. What happens when the work is performed on a separate thread? Where would
the exception be propagated to? The Observer does not have a chance to catch and handle this
exception (unless it occurs before the .subscribe() returns, which is unlikely in a non-blocking
function where all the interesting work is performed on a separate thread after the function returns).
Chapter 1: What is Reactive Programming? 11

RxJava provides a solution by letting the Observer provide an error callback. In RxJava, errors are
passed down the stream just like any other event. This allows the Observer to be reactive in the
face of failure in the same way it is reactive with normal events. Also, it does away with the verbose
try/catch construct, which most Java developers would love not having to deal with. We will discuss
more about error handling in Chapter 7.

Functional Reactive Programming (FRP)


There has been a lot of confusion over terminology around the industry. While reactive program-
ming includes elements of functional programming, it is debatable whether we can call it “func-
tional reactive programming”. Functional Reactive Programming (FRP) is a precise, mathematically
defined programming technique defined in 1997 by Conal Elliott and Paul Hudak. And Rx does
not conform to FRP’s precise definition or “continuous time” requirement where values change
continuously over time.
Still, a lot of different resources will still refer to Rx as “functional reactive programming”, much
to the discontent of Conal Elliott. The FRP creator has been everywhere from StackOverflow
to Twitter to call out misappropriations of his term, but “misuse” of the term has only spread
along with Rx’s popularity. Most of these Rx articles do so without knowledge of the original FRP
specification, although some do so in outright disregard of it because it is such a convenient term
to use when describing Rx.
This book will refrain from describing Rx as “functional reactive programming” or “FRP”. But we
did want to clarify the backstory and let you make your own decision on how to use the term and
how to interpret it as you come across it in other literature.

As you proceed through this book, keep in mind that there is a significant learning curve to reactive
programming. It requires a different way of thinking as compared to the regular imperative way
of doing things that most Java programmers are used to. But as with most changes in thinking,
hopefully there’s that a-ha moment where things start to click.
RxJava was designed to handle asynchronicity and event-driven conditions in a concise, functional,
resilient, and reactive way. The more complex your data streams are and the more inter-dependent
they are, the more value you’ll get out of using RxJava. When data streams (such as network
responses) need to be combined or nested, the old imperative way gets messy quickly; you’ll quickly
find yourself in “callback hell” trying to manage concurrency-related complexities. RxJava is the way
out of this hell.
If you’re lucky enough, however, to have a simple program with completely independent data
streams, then you may find RxJava to be overkill. Being direct and going imperative might be the
way to go in this case rather than dealing with the RxJava abstraction layer.
Regardless, it is worthwhile to learn reactive programming. RxJava is now pervasive across
platforms–from backend servers to mobile clients–and it has definitely cemented its place in the
Chapter 1: What is Reactive Programming? 12

Android ecosystem. RxJava is supported in many open-source Android libraries (Retrofit⁸, to name
one very important one). It’s being embraced by some of the top Android apps in the Play Store. And
Google even designed the new Android Architecture Components⁹ with RxJava in mind, embracing
many of its push-based, reactive concepts (the LiveData class was no doubt based on RxJava’s
Observable–there is an API to convert between the two–and the Room persistence library has an
option to return an RxJava Flowable). And as an open-source library itself, RxJava is constantly
being improved and adapted to developers’ needs.
As you can see, it will be difficult to avoid RxJava as an Android developer. It’s time to embrace it.
Learning RxJava will arm you with a powerful tool whether you choose to use it or not. Most likely,
it will come in quite handy with all the complexities that arise in the real world. So let’s dive right
in.
⁸http://square.github.io/retrofit/
⁹https://developer.android.com/topic/libraries/architecture/index.html
Chapter 2: RxJava Core Components
In the RxJava world everything can be modeled as a stream–a stream emits item(s) over time, and
each item can be transformed or modified as it passes through. An observer or consumer can then
subscribe and perform an action from each emission returned by the stream. Further, streams in
RxJava are highly composable and can even be combined with other streams to produce a desired
result.
If you think about it, a stream is not a new concept. A Collection in Java can be modeled as a
stream where each element in the Collection is an item emitted in the stream. On Android, click
events can be a stream, location updates can be a stream, push notifications can be a stream, and so
on.
Traditionally, processing data streams in Java is done imperatively. For example, given a list of User
objects, say we want to return only those that have a blog. That function might look something like:

1 /**
2 * Returns all users with a blog.
3 * @param users the users
4 * @return users that have a blog
5 */
6 public static List<User> getUsersWithABlog(List<User> users) {
7 List<User> filteredUsers = new ArrayList<>();
8 for (User user : users) {
9 if (user.hasBlog()) {
10 filteredUsers.add(user);
11 }
12 }
13 return filteredUsers;
14 }

The above code might look very familiar to you: a loop that iterates through each item in the provided
collection; an if-statement to check if a condition is true; and for those that pass, the necessary action
is performed (i.e. the item is added to the returned list).
Processing data streams is so commonplace that in Java 8 the package java.util.stream was
introduced. Essentially, the goal of Java 8 Streams is to increase the level of abstraction when dealing
with streams by providing a declarative way of doing so over the traditional imperative way. In
the imperative way shown above, we specified how to process a stream; but with a declarative
approach, we would simply specify what we want to do to that stream. This way of looking at
Chapter 2: RxJava Core Components 14

stream processing is ubiquitous in functional programming languages and is now introduced, along
with a few other functional programming constructs, as part of the core language. Using streams,
our above code would now look like:

1 /**
2 * Returns all users with a blog.
3 * @param users the users
4 * @return users that have a blog
5 */
6 public static List<User> getUsersWithABlog(List<User> users) {
7 return users.stream()
8 .filter(user -> user.hasBlog())
9 .collect(Collectors.toList());
10 }

Using streams, the same operation can be done much more concisely. First, we convert the List into
a Stream, filter the Stream by users that have a blog, and finally convert the Stream back into a List.
Now you might be wondering, if everything is a stream in RxJava and Java 8 supports streams, why
not just use Java 8’s streams? Although there are many reasons to prefer RxJava as we’ll see in the
book, at a very high-level, unlike Java 8 streams, RxJava enables us to do true reactive programming.
The toolbox of functional language constructs such as map, filter, and merge might be shared by
both, however, RxJava’s version of a stream is much easier to work with, and on top of that, shines
when dealing with asynchronicity.
Using our example, say the call user.hasBlog() is a network operation that blocks the current thread
until a response is received (probably not the desired implementation in production, but for educa-
tional purposes, say this were true). All things equal, both the imperative and Java 8 stream approach
of retrieval would block the thread invoking the method .getUsersWithABlog(List<User>). Thus,
the method cannot be called from the UI thread and some sort of approach that calls this method
from a background thread is required.
Using RxJava, the solution to this problem is trivial.

1 /**
2 * Returns all users with a blog.
3 * @param users the users
4 * @return an Observable emitting users that have a blog
5 */
6 public static Observable<User> getUsersWithABlog(List<User> users) {
7 return Observable.fromIterable(users)
8 .filter(user -> user.hasBlog())
9 .subscribeOn(Schedulers.io());
10 }
Chapter 2: RxJava Core Components 15

There are a few new classes here that we will definitely dive into, but first notice how the readability
has not been dramatically affected despite the operation now running on a background thread (i.e.
through .subscribeOn(Schedulers.io()). In essence, we have declaratively specified the thread
in which the operation should occur on. We did, however, modify the signature of the function by
returning an Observable<User>. As we will see, this is the first step towards reactive programming
on Android.

The 3 O’s: Observable, Observer, and Operator


The concept of a stream is modeled in RxJava using 3 main constructs which I like to call the “3
O’s”. These are the Observable, Observer and the Operator. The Observable is an entity that emits
item(s) over time (i.e. the stream). It can then be subscribed to at any point in time by an Observer
which will receive items that were pushed down along the stream. An Operator, or sequence of
Operators, can then be inserted in between the Observable and Observer to perform actions that
transform, filter, aggregate, and combine data emitted down the stream.

The 3 O’s of RxJava are the Observable, Observer and Operator. An Observable emits
items over time, an Observer subscribes to receive those items, and Operators can be
used to transform items emitted by the Observable including the Observable itself.

Observable and Observer Pair


An Observable can emit any number of items. As mentioned, to receive or listen to these emitted
items, an Observer needs to subscribe to the Observable. The .subscribe() method is defined by
the ObservableSource interface, which is implemented by Observable.

1 public interface ObservableSource<T> {


2 void subscribe(Observer<? super T> observer);
3 }

Once the Observable and Observer have been paired via .subscribe(), the Observer will receive
the following events through its defined methods:

• .onSubscribe(): this method is called along with a Disposable object which may be used to
unsubscribe from the Observable to stop receiving items
• .onNext(): this method is called when an item is emitted by the Observable
• .onComplete(): this method is called when the Observable has finished sending items
• .onError(): this method is called when an error is encountered within the Observable; the
specific error is passed to this method
Chapter 2: RxJava Core Components 16

1 public interface Observer<T> {


2 void onSubscribe(Disposable d);
3
4 void onNext(T value);
5
6 void onError(Throwable e);
7
8 void onComplete();
9 }

.onNext() can be invoked 0, 1, or multiple times by the Observable whereas .onComplete() and
.onError() are considered terminal events, meaning, if either of the two methods were called, no
further method would be invoked on the Observer. This is a crucial contract of an Observable that
must be enforced when creating an Observable.
The method .subscribe() is also an overloaded method of an Observable. Depending on the
Observable being subscribed to, sometimes it is not necessary to provide a “full” Observer when
subscribing. For example, if we know that the Observable will never invoke .onComplete() in the
case of an infinite stream, we can choose one of the other overloaded methods. The other options
are as follows (note that all these versions will return a Disposable object):

• .subscribe(): all methods are ignored. All errors will forward to the RxJavaPlugins.onError()
handler (more information on this in Chapter 7: Error Handling).
• .subscribe(Consumer<? super T> onNext): only .onNext() events are received. All errors
will forward to the RxJavaPlugins.onError() handler.
• .subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError): only
.onNext() and .onError() events are received and .onComplete() is ignored.
• .subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Ac-
tion onComplete): all events are received.
• .subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Ac-
tion onComplete, Consumer<? super Disposable> onSubscribe): all events are received;
additionally, a Consumer can be specified to receive the upstream’s Disposable object.

Previously in RxJava 1.x, if a method was omitted but called by the Observable (e.g. the .onCom-
plete() definition was not provided on subscription but called by the Observable), an exception
would have been thrown. However, this was changed in RxJava 2 so that you don’t have to provide a
method definition if you are not concerned with certain events. Although the API is more forgiving
now, you should still use an overloaded .subscribe() method with caution. In most cases, you
would want to provide an .onError() definition and handle the error as appropriate for your use
case.
Chapter 2: RxJava Core Components 17

Push vs. Pull

Looking at the Observable and Observer definitions, we can see that the design is inherently a push
based system. An Observer will react upon receiving an item that was pushed to it by the Observable
that it is subscribed to. However, this does not imply that emitted events are asynchronous. In fact,
by default an Observable is synchronous–events will be emitted in the Observable stream on the
same thread where .subscribe() is invoked.

1 Log.d(TAG, "Creating Observable.");


2 Observable.create((ObservableOnSubscribe<String>) emitter -> {
3 emitter.onNext("test");
4 emitter.onComplete();
5 }).subscribe(new Observer<String>() {
6 @Override
7 public void onSubscribe(Disposable d) {
8 }
9
10 @Override
11 public void onNext(String value) {
12 Log.d(TAG, "onNext(): " + value);
13 }
14
15 @Override
16 public void onError(Throwable e) {
17 }
18
19 @Override
20 public void onComplete() {
21 Log.d(TAG, "onComplete()");
22 }
23 });
24 Log.d(TAG, "After subscribing.");

The above code snippet will display in the console:

1 Creating Observable.
2 onNext() - test
3 onComplete()
4 After subscribing.

The resulting order of print statements is observed since RxJava does not specifically impose
asynchronous behavior. It is not opinionated about where the asychronicity originates unless it
is otherwise specified.
Chapter 2: RxJava Core Components 18

RxJava is synchronous by default. It is not opinionated about where asynchronicity


originates; it must be explicitly specified.

As you might guess, synchronous behavior may not be desired, and in many real-world cases, we
would want the underlying Observable to operate on a separate thread from the calling thread. The
power of RxJava lies in dealing with asynchronous streams, and we will look at how to do multi-
threading in RxJava in Chapter 4 - Multithreading. For now though, it is important to understand
that just because an Observer receives items via push does not mean that any sort of concurrency
is imposed.
RxJava also supports pulling from an Observable. Although this is not idiomatic RxJava, it was
included primarily for interoperability with codebases that aren’t 100% fully adapted to be reactive.
We will look at this more in Chapter 5 - Reactive Modeling on Android.

Operator
Operators are very powerful constructs that allow us to declaratively modify item emissions of
an Observable including the Observable/s themselves. Through Operators, we can focus on the
business logic that make our applications interesting rather than concerning ourselves with low-
level details of an imperative approach. Some of the most common operations found in functional
programming (such as map, filter, reduce, etc.) can also be applied to an Observable stream. Let’s
take a look at .map() as an example:

1 Observable<Integer> intObservable =
2 Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
3 emitter.onNext(1);
4 emitter.onNext(2);
5 emitter.onNext(3);
6 emitter.onNext(4);
7 emitter.onNext(5);
8 emitter.onComplete();
9 });
10
11 intObservable.map(val -> val * 3)
12 .subscribe(i -> {
13 // Will receive the following values in order: 3, 6, 9, 12, 15
14 });

The code snippet above would take each emission from the Observable and multiply each by 3,
producing the stream 3, 6, 9, 12, 15; but say we wanted to only receive even numbers. This can be
achieved simply by chaining a .filter() operation.
Chapter 2: RxJava Core Components 19

1 intObservable.map(val -> val * 3)


2 .filter(val -> val % 2 == 0)
3 .subscribe(i -> {
4 // Will receive the following values in order: 6, 12
5 });

As you can see from these examples, we were able to chain the operator .filter() and subsequently
subscribe to the stream. This is because RxJava was intentionally designed to have a fluent
interface¹⁰. A “fluent interface”, as coined by Martin Fowler and Eric Evans, is a style of interface
such that the return type of an object’s method is the same type as the object, or another type
depending on the action. In RxJava this means that applying an operator to an Observable will
return an Observable or another base reactive type. In other words, with a fluent interface design
we are able to perform operator method chaining which dramatically improves readability.
The astute reader might wonder: “what’s the point in using an operator? Why not just apply the
multiplication and check if the resulting number is even in the observer? Wouldn’t that be simpler?”

1 intObservable.subscribe(i -> {
2 int multipliedVal = i * 3;
3 if (multipliedVal % 2 == 0) {
4 // Will receive the following values in order: 6, 12
5 }
6 });

Indeed, the above code is functionally equivalent to applying the .map() and .filter() operators,
however, this approach is not encouraged. Not only is it not idiomatic reactive programming (i.e.
only values that you are actually interested in receiving should go through the Observer’s .onNext()
method), as more transformations are required from the stream, the complexity of the code in the
Observer significantly increases. But with the help of RxJava’s rich set of Operators, we are able to
reason about data transformations in a much simpler way. We will look into some more examples
in the next chapter, Chapter 3 - Operator Toolkit.

A series of simple, single-purposed operators are encouraged in RxJava. Data that


arrives in an Observer’s .onNext() should be in its final processed form.

Marble Diagrams
Marble diagrams are a common aid in visualizing Observables. Such diagrams are extensively used
throughout the RxJava wiki¹¹ and we will see several of them throughout the book. Say we have an
Observable emitting view clicks which are represented by an integer value:

¹⁰https://www.martinfowler.com/bliki/FluentInterface.html
¹¹https://github.com/ReactiveX/RxJava/wiki
Chapter 2: RxJava Core Components 20

Marble diagram of an Observable - Completed Successfully

The above marble diagram depicts clicks propagated down the stream as it is received over time. The
clicks are represented by an integer (the value of which doesn’t matter) and the stream completes
by invoking an Observer’s .onComplete() method. In Android, this successful completion might
mean that the user has backgrounded the app or completed the desired action on the screen, and
thus click events are no longer received.
On the other hand, say an error occurred to the Observable while view click events were being
propagated. For example, a view animation failed and so no further clicks should be propagated. In
this case, an Observer’s .onError() method would be invoked and no further events should occur
down the stream. In this event, the diagram would display an error using an “X”.
Chapter 2: RxJava Core Components 21

Marble diagram of an Observable - Error

Creating an Observable
Now that we’ve have a basic, high-level understanding of the different components of RxJava, let’s
dive into the Observable a bit more–specifically, different ways that we can create one. We’ve briefly
glanced at the most verbose way of creating an Observable (i.e. .create()); however, there are
simpler and more convenient APIs that are available to us. A few handy ones are:

Observable.just(T item)
.just() is one of the most common ways to wrap any Object to an Observable. It creates an
Observable of type T that just emits the provided item via an Observer’s .onNext() and then
completes via .onComplete(). Observable.just() is also overloaded and you can specify anywhere
from 1 to 9 items to emit.
Example usage:

1 Observable.just(1, 2, 3).subscribe(val -> {


2 // val will be 1, 2, 3
3 });

Observable.fromArray(T… items) and


Observable.fromIterable(Iterable<? extends T> iterable)
.fromArray() and .fromIterable() are used to create an Observable from an array and an
Iterable (e.g. List, Map, Set, etc.), respectively. Upon subscription, the resulting Observable will
Chapter 2: RxJava Core Components 22

emit the items in the array or Iterable and complete after.

Note that converting an array or Iterable can also be done using .just(); the generated
Observable would then be of type Observable<T[]> or Observable<List<T>> instead of type
Observable<T>. This is definitely allowed and sometimes necessary, however, it’s a bit cumber-
some since applying transformations require while/for loops through each item which undermines
the power of RxJava. If possible, seek to have an Observable as “flat” as possible.

Observable.range(int start, int count) and


Observable.rangeLong(long start, long count)
.range() and .rangeLong() will create an Observable<Integer> and Observable<Long>, respec-
tively. Both will emit a range of values starting from start up to, but not including, start + count.

Observable.empty()
.empty() returns no items and immediately invokes an Observer’s .onComplete() method when
subscribed to. By itself, it is not very useful and it’s commonly used in conjunction with other
operators.

Observable.error(Throwable exception)
.error() wraps an exception and invokes an Observer’s .onError() method when subscribed to.

Observable.never()
Creates an Observable that never invokes any of an Observer’s method when subscribed to. This is
primarily used for testing purposes.
All of the above methods for creating an Observable can be replicated by using .create(). For
example, Observable.just() can be implemented as:

1 public static <T> Observable just(T item) {


2 return Observable.create(emitter -> {
3 emitter.onNext(item);
4 emitter.onComplete();
5 });
6 }
Chapter 2: RxJava Core Components 23

As you can see, .create() is much more powerful and flexible in terms of constructing an
Observable and even allows you to violate the Observable contract (i.e. calling another event after
a terminal event has been invoked). For this reason, it’s much preferred to use any of the above
Observable convenience creation methods as they are safer and easier to use.

Something to note about the aforementioned methods for creating Observables is that for each
Observer that subscribes, each one will receive it’s own independent stream from start to finish. In
other words, all the emitted values from the subscribed Observable would be repeated. Observables
that behave this way are called cold Observables.

Cold vs. Hot Observable


An Observable is considered cold if it is not actively emitting items; it only starts emitting
items when it is subscribed to. Each subscription to a cold Observable will cause it to emit the
underlying sequence from beginning to end for each Observer. Note, however, that the exact values
of the sequence may differ for each Observer, depending on the underlying action the Observable
encapsulates as we’ll see in the next section.
Generally, a cold Observable is what you would want if you want a complete copy of events emitted
in the stream. It is what you want for operations that should only be invoked when subscribed to:
network operations, database queries, file I/O, etc.
Looking at .just() as an example, we see that the sequence is repeated on each subscription:

1 Observable observable = Observable.just("A", "B", "C", "D", "E");


2
3 // observer 1
4 observable.subscribe(val -> {
5 // "A", "B", "C", "D", "E" will be received in order
6 });
7
8 // observer 2
9 observable.subscribe(val -> {
10 // Again, "A", "B", "C", "D", "E" will be received in order
11 });

While cold Observables are subscriber-dependent, hot Observables on the other hand, are not. They
have their own timelines and actively emit items regardless if there are any subscribers. An Observer
would receive events starting from the point of subscription and wouldn’t receive any of the events
emitted prior to subscription. Hot Observables model processes that are temporal: a click event, an
event bus, etc.
Chapter 2: RxJava Core Components 24

Hot Observable

It is important to know whether or not a given Observable is cold or hot as it informs you on what
type of operations you should consider. For example, you might want to avoid Operators that cache
and aggregate emissions from hot Observables given that these type of Observables can in theory
produce an unlimited number of events (see Flowable). We will take a look more at hot Observables
in Chapter 5.

Lazy Emissions
An intrinsic property of a cold Observable is that it is lazy–the underlying sequence is only
computed and emitted on subscription time. To demonstrate this, let’s look at another Observable
creation method .fromCallable():

Observable.fromCallable(Callable<? extends T> callable)


.fromCallable() creates an Observable that when subscribed to, invokes the function supplied,
and then emits the value returned by that function.
Constructing an Observable with .fromCallable() won’t actually do the work specified inside
the Callable. All it does is define the work to be done. As such, .fromCallable() is the ideal
construction method to be used for any potentially long running UI-blocking operation. For example,
we can wrap a network call returning a User object by returning the value of the network call inside
the function provided to .fromCallable().
Chapter 2: RxJava Core Components 25

1 Observable<User> observable = Observable.fromCallable(() -> {


2 return apiService.getUserWithId(123);
3 });
4 observable.subscribe(user -> {
5 // Got user with ID 123
6 });

Observable.defer(Callable<? extends ObservableSource<?


extends T>> supplier)
.defer() is another Observable creation method available for deferring a potentially long running
UI-blocking operation. The main distinction between .defer() and .fromCallable() is that the
former returns an Observable in the supplied function.
.defer() creates an Observable that calls an ObservableSource factory to create an Observable
for each new Observer that subscribes.
The above code for retrieving a user by ID can then be rewritten as:

1 Observable<User> observable = Observable.defer(() -> {


2 return Observable.just(apiService.getUserWithId(123));
3 });
4 observable.subscribe(user -> {
5 // Got user with ID 123
6 });

The main reason to use .defer() over .fromCallable() is if the creation of an Observable in itself
is a blocking operation. However, these should in general be rare instances and .fromCallable()
should suffice.
.fromCallable() and .defer() should be used if the evaluation of a value takes some time to
compute and we would like to delay that computation up until the time of subscription. In contrast,
if .just() is used we would not be delaying that computation up until the time of subscription,
instead, the value would be computed immediately.
Chapter 2: RxJava Core Components 26

1 Observable<User> lazyObservable = Observable.fromCallable(() -> {


2 return apiService.getUserWithId();
3 });
4
5 // At this point, network call has not yet been made.
6 lazyObservable.subscribe(user -> {
7 // After subscribing, the network call is made and the user object is return\
8 ed
9 });
10
11 Observable<User> notLazyObservable = Observable.just(apiService.getUserWithId());
12
13 // At this point, the network call has already been made
14 // which blocks the calling thread.
15 notLazyObservable.subscribe(user -> {
16 // After subscribing, the network call has already been
17 // made on construction. The user object is still returned.
18 });

Although on subscription both Observers of lazyObservable and notLazyObservable receive the


User object, the time at which the function was evaluated differs. The lazily evaluated approach is
idiomatic RxJava and it also allows us to add asynchronous behavior whereas the other approach
does not. We will look into how we can add asynchronous behavior in Chapter 4: Multithreading).
Lastly, one other thing to note about laziness is that although the action is repeated on each
subscription, the actual emitted values of the sequence may differ. Using our example above, if
the User object was modified on the server between subscriptions, one Observer would receive the
older version of the User object, whereas the more recent Observer would receive the updated User
object.
Chapter 3: Operators
Now that we have established a foundation for the fundamentals of RxJava (i.e. the 3 O’s), we can
dive deeper into the rich set of Operators that are available to us. Through the contract defined by
the Observable, we are able to declaratively massage data emitted upstream to produce a desired
result. Arguably, the set of Operators and the ability to transform, combine, and aggregate items in
such a way is one of the main reasons why RxJava is so powerful. In this chapter, we will look at some
of the most commonly used Operators and provide several examples along with marble diagrams
to aid in visualizing how these Operators work. Not all Operators will be covered (as there are too
many to cover); however, after reading this chapter, you should have a good foundation for how
Operators work and learning new ones should be a breeze.

Transforming and Filtering


Operators that transform and/or filter are some of the handiest Operators that are available as those
do not require a timing or buffering aspect to it–the operations are applied as soon as a new element
is produced in the stream. In the previous chapter, we looked at map and filter to apply a simple
transformation and filtering of data. The following marble diagrams demonstrate how each one
affects emitted items before they are propagated to subscribers.

Map
.map() works by applying the mapper function provided on each item emitted upstream and passes
the return value from that function downstream.
Chapter 3: Operators 28

Marble diagram of .map()

Filter
.filter() works by applying the predicate on each emission. If the return value of the predicate is
true, the item will continue downstream, otherwise, it will be filtered out.

Marble diagram of .filter()

Say we had an Observable of Post objects that contain text and we are interested in processing a
Post’s text only if it contains a certain amount of characters (e.g. below 160 characters).
Chapter 3: Operators 29

1 Observable<Post> postObservable = // ...


2 postObservable.map(post -> post.text)
3 .filter(text -> text.length() < 160)
4 .subscribe(text -> {
5 // Receive text that is less than 160 characters
6 });

Notice that the .map() and .filter() operators are kept short and succinct. Although the same
action could have been done with a single Operator (i.e. just with .filter()), it is preferable to
break up operations into smaller actions as it improves readability and keeps each operation simple.
Something to note about using any Operator is that it is discouraged and non-idiomatic to mutate
state internally and externally from the stream. For example, it is bad practice to do the following:

1 List<String> allPostText = new ArrayList<>();


2 Observable<Post> postObservable = // ...
3 postObservable.map(post -> {
4 String text = post.text;
5 allPostText.add(text);
6 return text;
7 })
8 .filter(text -> text.length() < 160)
9 .subscribe(text -> {
10 // Receive text that is less than 160 characters
11 });

The reason this is discouraged is that mutating state internally and externally can have some
unintended side-effects. Each Operator is designed to return a new Observable leaving the original
Observable the way it was. This design makes reasoning simpler as it guarantees that each consumer
is independent and any unique chain of Operators applied by each one would not affect the
other. There are a few cases where it is difficult to get around this; for example, if you had an
Observable<List<T>> and wanted to sort each emission via Collections.sort(). These, however,
should be treated as exceptions and avoided if possible.

FlatMap
.flatMap() is another very common Operator that is used to transform emissions from an
Observable. The stream is transformed by applying a function that you specify to each emitted
item. However, unlike .map(), the function specified should return an object of type Observable. The
returned Observable is then immediately subscribed to and the sequence emitted by that Observable
is then merged and flattened along with subsequent emissions which are then passed along to the
observer.
Chapter 3: Operators 30

Marble diagram of .flatMap()

A common real-world example of using .flatMap() is for implementing nested network calls. Say
we have an Observable<User>, and for each User, we’d like to make a network call to retrieve that
user’s detailed information.
Assume we have the following methods available:

1 Observable<User> getUser(int userId) {


2 // Return an Observable<User> that performs a network
3 // request to retrieve a User with ID `userId`
4 }
5
6 Observable<UserDetail> getUserDetail(User user) {
7 // Return an Observable<UserDetail> that performs a
8 // network request to retrieve details about `user`
9 }

Chaining .getUser() with .flatMap() and having the function provided in .flatMap() return a
.getUserDetail() gives us:
Chapter 3: Operators 31

1 Observable<User> userObs = getUser(123);


2 Observable<UserDetail> detailObs = userObs.flatMap(user -> {
3 return getUserDetail(user);
4 });
5 detailObs.subscribe(userDetail -> {
6 // Received user's detail information here
7 });

Now you might still be wondering, what is the different between .map() and .flatMap() and when
should you be using one over the other? Perhaps a good way to see the difference between the two
is by changing our above example to use .map() instead.

1 Observable<User> userObs = getUser(123);


2 Observable<Observable<UserDetail>> detailObs = userObs.map(user -> {
3 return getUserDetail(user);
4 });
5 detailObs.subscribe(userDetailObservable -> {
6 // Received Observable<UserDetail> here, need to subscribe
7 // to it to receive its emission
8 userDetailObservable.subscribe(userDetail -> {
9 // Got user detail
10 });
11 });

Using .map(), the observer receives an object of type Observable<UserDetail> and thus needs to
subscribe to it to receive its emissions. With .flatMap(), this is not the case; the observer receives
a UserDetail, which, in our example, is the result the observer is interested in.
It is quite cumbersome for an observer to receive Observables. Imagine for a second that our
.getUser() method is implemented such that the observer receives updates to a User object (i.e.
the Observable stream can return multiple objects over time). Using .map(), we would receive
multiple Observable<User> objects which we would have to individually subscribe to and manage.
This is exactly the problem that .flatMap() solves. The operator will handle managing Observable
sequences emitted by the function you provide it so that the observer to .flatMap() receives a
flattened stream.
Since each emission from .flatMap() can return a new sequence, this has several implications: (1)
the returned Observable can have its own set of Operators applied to it, and (2) if there is a delay
between emissions, the emitted sequence can be interleaved with the sequence of other Observables
as depicted in the marble diagram. If this behavior of interleaving is not desired, .concatMap() can
be used instead.
Chapter 3: Operators 32

.flatMap() is also useful for introducing parallelism as we’ll see in Chapter 4: Multithreading.

ConcatMap
.concatMap() transforms emissions by invoking a function that you specify. Similar to .flatMap(),
the function you provide should also return an Observable. .flatMap() emissions, however, can be
interleaved because it will immediately subscribe to emitted Observables from the function provided
(see .flatMap() diagram for reference). .concatMap(), on the other hand, will not interleave
emissions. Instead, it will wait for the previous Observable to complete before subscribing to
subsequent ones.

Marble diagram of .concatMap()

Note the performance implications of using .concatMap()–if a returned Observable from .con-
catMap() takes a while to complete, subsequent emitted Observables will have to wait before sub-
scribed to. This trade-off should be kept in mind when deciding to use .flatMap() vs. .concatMap().

Skip
Other handy Operators allow you to consume only a subset of the items emitted by the sequence.
.skip(n) ignores the first n items emitted by the sequence and emits the remainder of the sequence.
.skip() is also overloaded with .skip(time, timeUnit) which skips any item/s emitted before the
specified time window.
Chapter 3: Operators 33

Marble diagram of .skip()

Take
Mirroring .skip(), .take(n) takes the first n items emitted by the sequence and completes
immediately after. Similarly, .take(time, timeUnit) only takes the item/s emitted in the specified
time window and ignores the rest.

Marble diagram of .take()

First & Last


.first() & .last() are pretty self-explanatory. Note, however, that these methods return a Single
rather than an Observable. A Single is a special subset of an Observable that emits just a single
Chapter 3: Operators 34

item rather than a sequence of items. It contains a subset of the Operators that an Observable given
its nature. We will look over Single in more detail in Chapter 5: Completable, Single, and Maybe

Marble diagram of .first()

Marble diagram of .last()

Notice for .last() that the item is not received immediately after it is emitted, it is received only
after the upstream sequence completes.

Combining
Oftentimes you may find the need to combine several Observable streams into a single stream.
Perhaps you have independent streams coming from multiple different sources and you would like to
Chapter 3: Operators 35

combine the results of these. Traditionally in Java, this task is especially difficult since synchronizing
and blocking to wait on data coming from different threads of execution is error-prone and hard to
debug. With RxJava, there are a few handy Operators that allow you to combine several streams
into a single unified stream.

Merge & Concat


There are several overloaded flavors of the .merge() Operator, all of which allow merging of
multiple Observable streams into a single stream.

Marble diagram of .merge()

Say, for instance, we wanted to combine the results of places recommended by 2 different recom-
mendation engines and merge the results of those two. If each recommendation was encapsulated
in an Observable, combining the results of these would be a trivial operation with .merge():

1 Observable<Place> getNearbyPlacesGoogle(Location location) {


2 // Method that makes a network call to a Google API
3 // to get all nearby places from `location`
4 }
5
6 Observable<Place> getNearbyPlacesFourSquare(Location location) {
7 // Method that makes a network call to Four Square's API
8 // to get all nearby places from `location`
9 }

Using the two methods defined for retrieving place recommendations, we can combine the results
of each through .merge():
Chapter 3: Operators 36

1 Observable<Place> allNearbyPlaces = Observable.merge(


2 getNearByPlacesGoogle(location),
3 getNearByPlacesFourSquare(location)
4 );
5 allNearbyPlaces.subscribe(place -> {
6 // Get all nearby places here
7 });

As soon as an Observer subscribes to the Observable allNearbyPlaces, each passed in Observable is


individually subscribed to internally in .merge() and the result is then merged and combined. Note
that from the marble diagram of .merge(), the resulting emissions can be interleaved, and once an
.onComplete() is received from an Observable, the merged Observable completes as well. If the
interleaving behavior is undesired, the .concat() Operator may be used to concatenate the results
rather than merge them. In effect, the passed in Observable instances are subscribed to serially
as each one completes rather than simultaneously. If the preceding Observable does not complete
however (i.e. an infinite stream), the subsequent Observable will not be subscribed to.

Marble diagram of .concat()

Zip
.zip() enables pair-wise zipping of emissions from multiple different Observables. It works by
combining the emission from each Observable using the specified combiner function. This is
especially handy when you have two data sources of different types that you would like to combine
into a single Observable source.
Chapter 3: Operators 37

Marble diagram of .zip()

Each zipped item is emitted in a strict sequence: the result of the 1st zipped item is the combination of
the 1st item in each stream, the 2nd zipped item is the combination of the 2nd item in each stream,
and so on. This implies that the zipped Observable will emit the same number of items emitted
by the Observable that has the fewest items; if one sequence does not emit any items, the zipped
Observable will also not emit any items.

The size of .zip()’s output sequence is the same size as the source Observable with the
smallest sequence. If one Observable does not emit any items, the zipped Observable
will also not emit any items.

Say for example we wanted to make 2 separate network calls to populate a user’s profile view. One
network call to retrieve a user’s detail information and another to get all the places they have been
before:

1 Observable<UserDetail> getUserDetail(User user) {


2 // Make network call to get `user`'s detailed information
3 }
4
5 Observable<List<Place>> getVisitedPlaces(User user) {
6 // Make network call to get all the places `user` has visited.
7 }

Using .zip() followed by combining the result into a android.support.v4.util.Pair object (a generic
wrapper that can hold two separate objects), we would get:
Chapter 3: Operators 38

1 Observable.zip(
2 getUserDetail(user),
3 getVisitedPlaces(user),
4 (userDetail, visitedPlaces) -> {
5 return new Pair(userDetail, visitedPlaces);
6 }).subscribe(pair -> {
7 UserDetail userDetail = pair.first;
8 List<Place> visitedPlaces = pair.second;
9
10 // Update profile view
11 });

Another thing to note about .zip() is that if one sequence emits much faster than another, internally,
.zip() will have to buffer the results of the faster Observable and wait until the slower Observable
emits an item. We will revisit some more implications of this in Chapter 7: Backpressure.

Aggregating
RxJava has several Operators that aggregate emissions from Observables to provide Observers
with an intended result. Operators that aggregate are typically stateful as internal state must
be maintained between emissions. A few commonly used aggregation Operators are .toList(),
.reduce(), and .collect().

ToList
.toList() converts an Observable<T> into an Observable<List<T>>. This is useful if the Observer
ultimately cares about a List<T> but the stream itself pushes objects of type T.
Chapter 3: Operators 39

Marble diagram of .toList()

Notice in the marble diagram that .toList() will only emit the buffered list once upstream emits
an .onComplete() notification. If .onComplete() is never invoked, .toList() will also never emit.
This is a common source of bugs for beginners and should be used with caution.
Using our example for all nearby places, we chain a .toList() call to provide the Observer with a
list of Place objects instead

1 Observable<Place> allNearbyPlaces = // ...


2 Observable<List<Place>> allNearbyPlacesList =
3 allNearbyPlaces.toList()
4 .subscribe(places -> {
5 // receive a list of places here
6 });

Reduce & Collect


.reduce() operates by applying an accumulator function on each emission to ultimately reduce the
stream to a single emission.
Chapter 3: Operators 40

Marble diagram of .reduce()

For example, say we had a stream that emits integers and we are interested in computing the
summation of those integers. For that, we can use .reduce() to accumulate the sum.

1 Observable<Integer> intStream = // ...


2 intStream.reduce(
3 (i1, i2) -> i1 + i2
4 ).subscribe(total -> {
5 Log.d(TAG, "Total is: " + total);
6 });

In our example, i1 is the summation of previous emissions, and i2 is the current integer emission.
The starting value for i1 is 0, but .reduce() also has an overloaded version where a different starting
(seed) value may be specified. .reduce() however should not be used for accumulating data into a
mutable data structure. For this, .collect() should be used.
.collect() operates very similarly to .reduce(), but instead of taking in an accumulator function,
we pass it a Callable that emits the mutable data structure, followed by a BiConsumer that modifies
the mutable data structure.
Chapter 3: Operators 41

Marble diagram of .collect()

For example, say we had an Observable that emits a list of words. We can accumulate the list of
words in a StringBuilder:

1 final Observable<String> wordStream = // ...


2 wordStream.collect(() -> {
3 return new StringBuilder();
4 }, (stringBuilder, s) -> {
5 stringBuilder.append(" ");
6 stringBuilder.append(s);
7 }).subscribe(stringBuilder -> {
8 Log.d(TAG, stringBuilder.toString());
9 });

Utility Operators
RxJava has a handful of utility Operators that don’t necessarily modify the emissions themselves
through transformations/filters, but instead allow you to do various actions such as getting insight
into events in the stream itself (for debugging/logging purposes) or caching results emitted in the
stream.

DoOnEach
.doOnEach() is an Operator that enables listening to events that occur in an Observable stream (i.e.
when .onNext(), .onError() and .onComplete() are invoked) by providing an Observer. Generally,
Chapter 3: Operators 42

this Operator is used if you would like to perform a side-effect when an event occurs. There are
also several .doX() Operators–such as .doOnNext(), .doOnError() and .doOnComplete()–that are
available if you’re interested in listening only to a specific event.

Marble diagram of .doOnEach()

Some common usages for .doX() Operators is for logging purposes. Say we had a chain of operators
in a stream and we would like to log each time an Operator is about to be applied.

1 Observable<Integer> intStream = Observable.range(1, 3);


2 intStream.doOnNext(i -> Log.d(TAG, "Emitted: " + i))
3 .map(i -> i * 2)
4 .doOnNext(i -> Log.d(TAG, "map(): " + i))
5 .filter(i -> i % 2 == 0)
6 .doOnNext(i -> Log.d(TAG, "filter(): " + i))
7 .subscribe(i -> {
8 Log.d(TAG, "onNext(): " + i);
9 });

As expected, the following code snippet would log on the console the result of each operation (new
lines added for readability).
Chapter 3: Operators 43

1 Emitted: 1
2 map(): 2
3 filter(): 2
4 onNext(): 2
5
6 Emitted: 2
7 map(): 4
8 filter(): 4
9 onNext(): 4
10
11 Emitted: 3
12 map(): 6
13 filter(): 6
14 onNext(): 6

Of course logging can also be performed within the Operators themselves, however, this should be
avoided as it doesn’t stay true to the philosophy of maintaining single/simple purposed Operators.

Cache
.cache() is a handy Operator that subscribes lazily to an Observable and caches all of the events
emitted in the Observable so that when another Observer subscribes at a later point, the cached
events will be replayed. .cache() can be used when you would like to reuse events that were already
computed versus having to recompute the events all over again.

Marble diagram of .cache()


Chapter 3: Operators 44

Say you need to make a network call to obtain app-specific settings (e.g. feature flags, server-
generated strings, etc.). This network call needs to be made when the app first comes to the
foreground and the result of which should be reused throughout the app. One way to solve this
is by using .cache() and reusing the resulting Observable’s initial emission.

1 Observable<Timed<AppSettings>> appSettingsObservable =
2 Observable.fromCallable(() -> {
3 return apiService.getAppSettings();
4 }).timestamp().cache();
5
6 // Make 1st network call when app comes to foreground.
7 appSettingsObservable.subscribe(result -> {
8 Log.d(TAG, "Time computed on foreground: " + result.time());
9 });
10
11 // Get settings at a later point in the app
12 appSettingsObservable.subscribe(result -> {
13 Log.d(TAG, "Time computed cached: " + result.time());
14 });

In addition to .cache(), we’ve also added a .timestamp() call which is another utility Operator
that wraps an emission in a Timed object–a class that wraps an arbitrary object (in this case, the
retrieved AppSettings) along with a timestamp of when the item was emitted. Running this, we
would verify that the AppSettings was indeed reused rather than recomputed.

1 Time computed on foreground: 1488282552026


2 Time computed cached: 1488282552026

Reusing Operator Chains


As mentioned earlier in Chapter 2, using an Operator should be kept single-purposed. If multiple
transformations need to be applied to an emission, each transformation should be encapsulated in
its own Operator. This approach is declarative (i.e. it describes what should be done, not how it
should be done) which aids in readability.
As such, you might find yourself repeating the same chain of Operators in parts of your codebase.
For example, say it was a very common action in one of your classes to filter by some condition,
skip the first filtered item, followed by taking the first result after skipping:
Chapter 3: Operators 45

1 someObservable.filter(this::isConditionSatisfied)
2 .skip(1)
3 .take(1)
4 // ...continue with other operations here

In the spirit of the DRY (i.e. don’t repeat yourself) principle, these repeated operator chains can
be shared and reused by using an ObservableTransformer and passing that as a parameter to the
.compose() operator.

In addition to ObservableTransformer, other XTransformer classes exist for transforming other


base reactive types (see Chapter 5: Completable, Single and Maybe).

ObservableTransformer
An ObservableTransformer allows us to compose/transform Observables. In our example above,
we can encapsulate the three operators–namely, .filter(), .skip() and .take()–inside of an
ObservableTransformer and reuse it across other Observables.

1 public class MyTransformer <T> implements ObservableTransformer<T, T> {


2
3 private final Predicate<? super T> filterVal;
4 private final int skipVal;
5 private final int takeVal;
6
7 MyTransformer(
8 Predicate<? super T> filterVal,
9 int skipVal,
10 int takeVal
11 ) {
12 this.filterVal = filterVal;
13 this.skipVal = skipVal;
14 this.takeVal = takeVal;
15 }
16
17 @Override
18 public ObservableSource<T> apply(Observable<T> upstream) {
19 return upstream.filter(filterVal)
20 .skip(skipVal)
21 .take(takeVal);
Chapter 3: Operators 46

22 }
23 }

The class MyTransformer implements ObservableTransformer and has the overridden method
.apply() where we are passed in the source Observable. Within it, we apply the necessary
transformations and return the resulting Observable.
To use this, we would create an instance of MyTransformer and pass it via .compose():

1 someIntObservable.compose(
2 new MyTransformer<Integer>(this::isConditionSatisfied, 1, 1)
3 )
4 // ...continue with other operations here

As you can see, using .compose() along with an ObservableTransformer promotes code reuse, and
if any changes are needed in the operator chain, we would simply update the operator chain inside
MyTransformer.

Now, what about code reuse by using a plain-old Java method and calling it from within an
Operator? Technically that can also work, but it all depends on the operation to be applied. For
example, if you need to transform every single emission in a stream, we can simply call a method
from within a .map() operator:

1 someIntObservable.map(this::transform)

However, in our previous example, we are not applying a transformation for every single emission.
Instead, we are filtering the stream by some condition and taking the 2nd result from that filter. In
other words, we need to transform the stream itself to obtain the result we are interested in. With
.compose(), we can do just that and reuse multiple Operators together.
Chapter 4: Multithreading
From the previous chapters, we have looked at the Observable and the Observer pair along with
several Operators that can modify emissions from an Observable stream. So far we have avoided
dealing with any sort of concurrency; however, one of the hallmarks of RxJava is that it simplifies
working with concurrent tasks. While traditional Java/Android threading options such as Threads,
Executors, and AsyncTasks are still available and can be used in conjunction with RxJava, RxJava
offers its own threading model that works well within the stream abstraction. In this chapter, we
will go through these constructs and show you how you can control which thread each computation
should occur on.

Asynchronicity
It is a common misconception that RxJava is inherently asynchronous–perhaps the reason for this
confusion is because Observables are push instead of pull by nature. But, in fact, Observable streams
are synchronous by default unless otherwise specified.
Given that Observable streams are synchronous by default, can you guess the order of the Logcat
statements in the following example…?

1 Observable<Integer> integerObservable = Observable.create(source -> {


2 Log.d(TAG, "In subscribe");
3 source.onNext(1);
4 source.onNext(2);
5 source.onNext(3);
6 source.onComplete();
7 });
8 Log.d(TAG, "Created Observable");
9
10 Log.d(TAG, "Subscribing to Observable");
11 integerObservable.subscribe(i -> Log.d(TAG, "In onNext(): " + i));
12
13 Log.d(TAG, "Finished");

Unsurprisingly, the above code will print out the following:


Chapter 4: Multithreading 48

1 Created Observable
2 Subscribing to Observable
3 In subscribe
4 In onNext(): 1
5 In onNext(): 2
6 In onNext(): 3
7 Finished

As soon as .subscribe() was invoked, control was passed to the Observable to generate and emit its
data stream. In other words, the .subscribe() call causes the Observable to do the work specified
in the function that was passed to the .create() method. But what happens if this work is a long-
running operation (which in many real-world cases, it would be)? If it is invoked on Android’s
main UI thread, then we have problems… namely, user input being blocked leading to the dreaded
“Application Not Responding” (ANR) dialog.

Adding Asynchronicity
There are many ways we can add asynchronicity so that the function within .create() is invoked
on a separate thread from the calling thread. As mentioned in Chapter 2, RxJava is agnostic as to
how asynchronicity is accomplished. One way is to make use of a plain old Thread. Let’s take our
previous example… instead of immediately calling .onNext() in the function provided in .create(),
we will…

1. … wrap the .onNext() and .onComplete() calls in a Runnable,


2. … provide the Runnable to a new Thread,
3. … and then start the Thread.

1 Observable<Integer> integerObservable = Observable.create(source -> {


2 Log.d(TAG, "In subscribe");
3 new Thread(() -> {
4 source.onNext(1);
5 source.onNext(2);
6 source.onNext(3);
7 source.onComplete();
8 }).start();
9 });
10 Log.d(TAG, "Created Observable");
11
12 Log.d(TAG, "Subscribing to Observable");
13 integerObservable.subscribe(i -> Log.d(TAG, "In onNext(): " + i));
14
15 Log.d(TAG, "Finished");
Chapter 4: Multithreading 49

With this change, we now get:

1 Created Observable
2 Subscribing to Observable
3 In subscribe
4 Finished
5 In onNext(): 1
6 In onNext(): 2
7 In onNext(): 3

As we can see, the “Finished” statement is invoked before the “onNext()” statements. In fact, the
order of these statements are no longer deterministic and our original log sequence is still possible;
it all depends on when the OS decides to perform a context switch, which can change from one
execution to the next.
This approach to non-blocking subscription is perfectly valid as long as an invocation to .onNext(),
.onError(), or .onComplete() is performed from a single thread and that it is thread-safe. If this
contract is breached, some Operators that depend on this assumption may fail to function (i.e. we
cannot emit events from multiple threads).
The above example was used to show that a plain old Thread (and any other Java/Android threading
construct) can be used to add asynchronicity to RxJava. However, just because using these is possible
does not mean that they should be used. The preferred way of achieving concurrency in RxJava is
actually through the use of Schedulers.

Schedulers
A Scheduler is a multithreading construct introduced in RxJava that can run a scheduled unit of
work on a thread. Simplistically, you can think of a Scheduler as a thread pool, and when a task
needs to be executed, it takes a single thread from its pool and runs the necessary task. Schedulers are
used in conjunction with .subscribeOn() and .observeOn(), two Operators that specify where a
particular operation should execute. When a Scheduler is specified along the Observable chain, the
Scheduler will provide a worker that will run the actual block of code. The thread that the scheduled
work executes on depends on the Scheduler in use. There are several types of Schedulers available
via factory methods in the Schedulers class:

• Schedulers.newThread(), as its name suggests, returns a Scheduler that will create a new
Thread for each scheduled unit of work. As a result, using Scheduler.newThread() is
expensive since a new Thread is spawned each time–no reuse happens.
• Schedulers.from(Executor executor) returns a Scheduler that is backed by the specified
Executor.
Chapter 4: Multithreading 50

• Schedulers.single() returns a Scheduler that is backed by a single thread. If several tasks are
scheduled in Schedulers.single(), the tasks are scheduled serially and will be executed in
order.
• Schedulers.io() provides a Scheduler that is meant for I/O-bound work such as network calls,
database transactions, etc. The underlying implementation uses an Executor thread pool that
will grow as needed. With I/O tasks, we are not doing CPU-intensive work; instead, we are
usually waiting on resources or services that may live on a different host, so being able to
create and assign a new thread to each task is ideal.
• Schedulers.computation() provides a Scheduler that is meant for computational or CPU-
intensive work such as processing a long list, resizing an image, etc. This Scheduler utilizes
a thread pool whose size is bounded by the number of available cores. Because we are
performing CPU-intensive work, creating more threads than cores will actually degrade
performance; both thread creation and context switching result in a lot of overhead without
helping to speed up our CPU-intensive work. The .computation() Scheduler should never be
used for I/O, and the .io() Scheduler should never be used for computational work; I/O and
computation block for completely different reasons thereby requiring completely different
threading strategies.
• Schedulers.trampoline() provides a Scheduler that schedules work on the current thread
(i.e. using this Scheduler will block the current thread). Scheduled tasks are not executed
immediately and instead are put in a queue and executed after the current unit of work is
completed. This particular Scheduler is typically used when implementing recursion to avoid
infinitely growing the call stack.

Observable.subscribeOn()
The .subscribeOn() operator is used in the Observable chain to dictate where the Observable
should operate (i.e. the function inside of .create()). Rewriting the previous example using a
Scheduler instead gives us:

1 Observable<Integer> integerObservable = Observable.create(source -> {


2 Log.d(TAG, "In subscribe");
3 source.onNext(1);
4 source.onNext(2);
5 source.onNext(3);
6 source.onComplete();
7 });
8 Log.d(TAG, "Created Observable");
9
10 Log.d(TAG, "Subscribing to Observable");
11 integerObservable.subscribeOn(Schedulers.newThread())
12 .subscribe(i -> Log.e(TAG, "In onNext(): " + i));
13
14 Log.d(TAG, "Finished");
Chapter 4: Multithreading 51

Running the above code is similar to using a Thread in that the operations inside .create() will
now occur in a separate thread provided by Schedulers.newThread(). The benefit of this approach
over using a Thread is that tacking on a Scheduler to specify where the Observable should execute
is declarative and we no longer have to worry about the low-level details of how to create and run
a thread. Furthermore, we can decouple the Observable creation from the threading; the subscriber
can determine the thread on which to run the Observable rather than having that decision baked
into the Observable itself.

.subscribeOn() controls what Scheduler is used to execute the statements inside the
.create().

Observable.observeOn()
Using .subscribeOn(), we are able to modify where an Observable does its work. But say, for
example, that we performed a network call to retrieve a User’s information using Schedulers.io()
and we want to update the UI once the network call succeeds. Can you spot the bug in the following
line of code?

1 // `userObservable` retrieves a User object over the network


2 Observable<User> userObservable = // ...
3
4 userObservable.subscribeOn(Schedulers.io())
5 .subscribe(user -> textView.setText(user.getName()));

As you might have noticed in the preceding example, all subsequent operations after .sub-
scribeOn() will run on the thread provided by the specified Scheduler. In other words, the call
to textView.setText(user.getName()) will run on a thread other than the UI thread, which will
cause the app to crash with a CalledFromWrongThreadException. To circumvent this issue, we can
wrap the call to update the TextView in a Runnable and have it run on the main thread; however,
doing that is about as elegant as our plain old Thread example above. Ideally, we want a declarative
approach to switch threads and post emissions to a separate thread (in this case, to the Android main
thread). For this, we make use of the .observeOn() operator.
.observeOn() modifies the Observable so that its emissions will be posted in the provided
Scheduler. .observeOn() is the Operator we want if we want the downstream consumer to operate
on a separate thread. To fix the code above, we would simply add an .observeOn() before the
.subscribe() call.
Chapter 4: Multithreading 52

1 // `userObservable` retrieves a User object over the network


2 Observable<User> userObservable = // ...
3
4 userObservable.subscribeOn(Schedulers.io())
5 .observeOn(AndroidSchedulers.mainThread())
6 .subscribe(user -> textView.setText(user.getName()));

Running the above code will now execute textView.setText(user.getName()) in the Android main
thread. Note that the Scheduler we used is AndroidSchedulers.mainThread(), which is provided
by the RxAndroid¹² extension library to RxJava.

Scheduler Behavior Details


As you can see, using .subscribeOn() and .observeOn() make threading trivially easy, but there
are some intricacies to these operators that need to be called out.
As pointed out earlier, where in the operator chain the .subscribeOn() call appears does not
matter. However, it’s important to note that only the first .subscribeOn() call will be applied; any
subsequent .subscribeOn() calls will have no effect. Oftentimes, Observables are created as part
of a library or API and provided to a client via some interface. This interface documentation should
clearly state if the returned Observable will have already been relegated to some Scheduler via
.subscribeOn() because, if it has, the client will no longer be able to make its own .subscribeOn()
call. In general, it is recommended that the creator of the Observable not call .subscribeOn() to
allow for flexibility by the client. For example, the client may already be operating on a background
thread and has no need for the Observable to create yet another thread to perform its work. If, for
some reason, you do not want the caller to be able to modify the Scheduler where the Observable
executes, simply add a .subscribeOn() call to the Observable that you pass back.

Only the first .subscribeOn() call—-no matter where it is in the operator chain—-will
be applied to the source Observable at the time .subscribe() is called; any subsequent
.subscribeOn() calls will have no effect.

It is advised for .subscribeOn() to be placed first in the operator chain. Doing this will
be clearer for a human reader since .subscribeOn() applies to the start of data stream.

.observeOn(), on the other hand, is the dual of .subscribeOn() in many ways. Whereas .sub-
scribeOn() affects the upstream source Observable, .observeOn() affects the downstream opera-
tors. And whereas only the first .subscribeOn() takes effect, .observeOn() can be called multiple
times, with each call switching the thread for downstream operators (until another .observeOn()
call is encountered). For common use cases (e.g. where the Observer is updating the UI), it is
¹²https://github.com/ReactiveX/RxAndroid
Chapter 4: Multithreading 53

recommended to put the .observeOn() call as close to the .subscribe() call (i.e. as late in the
Operator chain) as possible. This will ensure the computation performed by the Operators does
not occur on the main UI thread, which we generally want to keep unburdened. And since thread
switches bear some performance cost, we also don’t want to perform them early on in the stream
for items that may just get filtered out later on.
To reinforce the previous points, let’s take a look at a completely-non-real-world example. To help
show which thread each operator is running on, let’s define the following print() method:

1 public static void print(String message) {


2 String threadName = Thread.currentThread().getName();
3 Log.d(TAG, threadName + " : " + message);
4 }

And taking our Observable from before, let’s add a series of .subscribeOn() and .observeOn()
calls to the chain to see what happens:

1 Observable<Integer> observable = Observable.create(source -> {


2 print("In subscribe");
3 source.onNext(1);
4 source.onNext(2);
5 source.onNext(3);
6 });
7
8 observable.subscribeOn(Schedulers.computation()) // "RxComputationThreadPool-1"
9 .doOnNext(value -> print("(a) : " + value))
10 .observeOn(Schedulers.newThread()) // "RxNewThreadScheduler-2"
11 .doOnNext(value -> print("(b) : " + value))
12 .observeOn(Schedulers.newThread()) // "RxNewThreadScheduler-3"
13 .subscribeOn(Schedulers.newThread()) // This has no effect.
14 .doOnNext(value -> print("(c) : " + value))
15 .observeOn(Schedulers.newThread()) // Overwritten by next observeOn().
16 .observeOn(AndroidSchedulers.mainThread()) // "main"
17 .subscribe(value -> print("(d) : " + value));
18 }

This code prints out the following output:


Chapter 4: Multithreading 54

1 RxComputationThreadPool-1 : In subscribe
2 RxComputationThreadPool-1 : (a) : 1
3 RxComputationThreadPool-1 : (a) : 2
4 RxComputationThreadPool-1 : (a) : 3
5 RxNewThreadScheduler-2 : (b) : 1
6 RxNewThreadScheduler-2 : (b) : 2
7 RxNewThreadScheduler-2 : (b) : 3
8 RxNewThreadScheduler-3 : (c) : 1
9 RxNewThreadScheduler-3 : (c) : 2
10 RxNewThreadScheduler-3 : (c) : 3
11 main : (d) : 1
12 main : (d) : 2
13 main : (d) : 3

• Notice in the above code that the thread specified in the .subscribeOn() call on Line 8
(RxComputationThreadPool-1) applies to both the source Observable as well as subsequent
operators until Line 10, when a new thread (RxNewThreadScheduler-2) is specified by the
.observeOn() call.
• Each .observeOn() call then changes the thread that the stream runs on until the next
downstream .observeOn() call.
• Lastly, notice that the .subscribeOn() call on Line 13 has no effect on the output; there would
be no difference if we had inserted that call anywhere from Line 9 to Line 16 or removed it
completely; it’s made completely irrelevant because of our earlier .subscribeOn() call on
Line 8.

Concurrency with FlatMap


So far, we have looked at ways to introduce multithreading through the use of Schedulers along
with the .subscribeOn() and .observeOn() operators. To achieve true concurrency, however, these
operators alone are not sufficient.
If you noticed in our example of using .subscribeOn(), events received from upstream were not pro-
cessed on separate threads–all emissions were executed on the same thread (i.e. RxCachedThreadScheduler-
1). To achieve true concurrency, we would need the help of .flatMap().
Say, for example, we wanted to get the corresponding User object given a list of usernames.
Chapter 4: Multithreading 55

1 class User {
2 final String username;
3 // Other user fields go here...
4
5 User(String username) {
6 this.username = username;
7 }
8 }
9
10 class NetworkClient {
11 Random random = new Random();
12
13 User fetchUser(String username) {
14 // perform blocking network call here but for the sake of the example,
15 // mimic network latency by adding a random thread sleep and return
16 // a new User object
17 randomSleep();
18 return new User(username);
19 }
20
21 void randomSleep() {
22 try {
23 Thread.sleep(random.nextInt(3) * 1000);
24 } catch (InterruptedException e) {
25 e.printStackTrace();
26 }
27 }
28 }

Using the defined classes, we can make the network calls to fetch the User objects:

1 NetworkClient networkClient = new NetworkClient();


2 String[] usernames = new String[] {
3 "john", "mike", "jacob"
4 };
5 Observable.fromArray(usernames)
6 .subscribeOn(Schedulers.io())
7 .map(networkClient::fetchUser)
8 .subscribe(user -> print("Got user: " + user.username));
9 }

The first two lines initialize the NetworkClient object as well as a usernames String array. We
then convert usernames into an Observable<String> using the Observable.fromArray() creation
Chapter 4: Multithreading 56

method. The .map() operator then retrieves the User object given a username which is then emitted
to the observer.
Running this code would give us:

1 RxCachedThreadScheduler-1 : Got user: john


2 RxCachedThreadScheduler-1 : Got user: mike
3 RxCachedThreadScheduler-1 : Got user: jacob

Looking at the order of the printed statements, each User is fetched in the same order that it appears
in the usernames array. The operation in .map() (i.e. .fetchUser()) will block until it completes
before it can process another username. However, there is no reason that we need to wait for the
network call to complete before retrieving another User object. All of these network requests can
run concurrently.
As we’ve seen in the previous chapter, using .flatMap(), we are able to return a new Observable
given an upstream emission; the returned Observable from .flatMap() is completely independent
and we can even specify a separate Scheduler for that Observable to operate in. In this way, we can
impose concurrent behavior in an Observable chain.
Modifying the code above to use .flatMap() instead of .map(), we get:

1 Observable.fromArray(usernames)
2 .subscribeOn(Schedulers.io())
3 .flatMap(username ->
4 Observable.fromCallable(() ->
5 networkClient.fetchUser(username)
6 ).subscribeOn(Schedulers.io())
7 )
8 .subscribe(user -> print("Got user: " + user.username));
9 }

Running the above code gives us:

1 RxCachedThreadScheduler-3 : Got user: jacob


2 RxCachedThreadScheduler-2 : Got user: mike
3 RxCachedThreadScheduler-1 : Got user: john

Notice that the operations to fetch a User were now run on separate threads (i.e. RxCachedThreadScheduler-
3, RxCachedThreadScheduler-2 and RxCachedThreadScheduler-1), essentially unblocking execution
of User fetches. As a side-effect of introducing concurrency, however, the order of emissions from
.flatMap() may no longer be the same as the order of events received upstream.
Part 2: RxJava Advanced
Chapter 5: Reactive Modeling on
Android
By now you should have a good understanding of the basic concepts of RxJava. We covered the
building blocks which are composed of the 3 O’s: the Observable, the Observer, and the Operator.
We’ve also looked at several functional style operations in the RxJava toolkit that transform, combine
and aggregate emissions from an Observable until we received a desired result. You should now also
have a pretty good sense of how RxJava can simplify dealing with concurrent processes inherent in
developing mobile apps through the use of Schedulers. Collectively, these tools allow us to program
in Android in a way that is declarative over the traditional imperative approach.
In this chapter, we will combine all the lessons learned so far and go over some examples of what
can be modeled from the non-reactive Android world into the reactive world. We will also go over
a few new concepts that will ultimately aid in making the transition to a reactive codebase.

Bridging Non-Reactive into the Reactive world


One of the challenges of adding RxJava as one of the libraries to your project is that it fundamentally
changes the way that you reason about your code.
RxJava requires you to think about data as being pushed rather than being pulled (See Chapter
2: Push vs Pull). While the concept itself is simple, changing a full codebase that is based on a pull
paradigm can be a bit daunting. Although consistency is always ideal, you might not always have the
privilege to make this transition throughout your entire code base all at once, and so an incremental
approach may be needed.
Consider the following:

1 /**
2 * @return a list of users with blogs
3 */
4 public List<User> getUsersWithBlogs() {
5 List<User> allUsers = UserCache.getAllUsers();
6 List<User> usersWithBlogs = new ArrayList<>();
7 for (User user : allUsers) {
8 if (user.blog != null && !user.blog.isEmpty()) {
9 usersWithBlogs.add(user);
10 }
Chapter 5: Reactive Modeling on Android 59

11 }
12 Collections.sort(
13 usersWithBlogs,
14 (user1, user2) -> user1.name.compareTo(user2.name)
15 );
16 return usersWithBlogs;
17 }

This function gets a list of User objects from the cache, filters each one based on if the User has a
blog or not, sorts them by the User’s name, and finally returns them to the caller. Looking at this
snippet we notice that much of these operations can take advantage of RxJava operators. Namely,
.filter() and .sorted().
As the name implies, .sorted() is an aggregate operator that sorts emissions from the Observable;
the emitted object must implement Comparable, or alternatively, you can pass a Comparator object
to specify how the emissions should be sorted.
Rewriting this snippet then gives us:

1 /**
2 * @return a list of users with blogs
3 */
4 public Observable<User> getUsersWithBlogs() {
5 return Observable.fromIterable(UserCache.getAllUsers())
6 .filter(user -> user.blog != null && !user.blog.isEmpty())
7 .sorted((user1, user2) -> user1.name.compareTo(user2.name));
8 }

The first line of the function converts the List<User> returned by UserCache.getAllUsers() to
an Observable<User> using the Observable creation method .fromIterable(). This is the first
step into making our code reactive. Now that we are operating on an Observable, this enables us
to perform any Observable operator in the RxJava toolkit: filter() and sorted() in this case.
.filter() will filter out users that do not have blogs, and .sorted() will sort users that have blogs
alphabetically by name.
There are a few other points to note about this change.
First, the method signature is no longer the same. This may not be a huge deal if this method call
is only used in a few places and it’s easy to propagate the changes up to other areas of the stack;
however, if it breaks clients relying on this method, that is problematic and the method signature
should be reverted.
Second, RxJava is designed with laziness in mind (See Chapter 2: Lazy Emissions). That is, no
long operations should be performed when there are no subscribers to the Observable. With this
modification that assumption is no longer true since UserCache.getAllUsers() is invoked even
before there are any subscribers. Whether or not the backing cache is in-memory or on disk, to stay
true to RxJava principles, this operation should be postponed until an Observer subscribes to it.
Chapter 5: Reactive Modeling on Android 60

Leaving the Reactive world


To address the first issue from our change, we can make use of any of the .blockingX() operators
available to an Observable. Essentially, a .blockingX() operator will block the calling thread until
an item is emitted downstream. A few notable blocking operators that are available are:

• .blockingFirst(): blocks the calling thread and returns the first element emitted by the
Observable.
• .blockingNext(): returns an Iterable which allows you to iterate through all the emissions
by the Observable. Each iteration will block until the Observable emits a next item.
• .blockingLast(): blocks the calling thread and returns the last element emitted by the
Observable.
• .blockingSingle(): blocks the calling thread until the Observable emits an element followed
by an .onComplete() event, otherwise, an Exception is thrown.
• .blockingSubscribe(): blocks until a terminal event is received (all elements that are received
through .onNext() are ignored).

Using a blocking operator to change the method signature back to a List<User>, our snippet would
now look like:

1 /**
2 * @return a list of users with blogs
3 */
4 public List<User> getUsersWithBlogs() {
5 return Observable.fromIterable(UserCache.getAllUsers())
6 .filter(user -> user.blog != null && !user.blog.isEmpty())
7 .sorted((user1, user2) -> user1.name.compareTo(user2.name))
8 .toList()
9 .blockingFirst();
10 }

Before calling a blocking operator (i.e. in this case, .blockingFirst()) we first need to chain
the aggregate operator .toList() so that the stream is modified from an Observable<User> to a
Single<List<User>>. Afterwards, we can then call the blocking operator .blockingFirst() which
unwraps the Single and returns a List<User>.

A Single is a special type of Observable that emits a single item. As opposed to the Observable
which can emit any of the 3 events: .onNext(), onCompleted(), and .onError(), Single only
has an .onSuccess() and an .onError(). Using Single is preferred when we know that only a
single item will be emitted as it offers the caller a clearer intent as to what data will be emitted in
Chapter 5: Reactive Modeling on Android 61

the stream (i.e. a single item). We will revisit Singles again later in this chapter (See Chapter 5:
Completable, Single and Maybe).

Although RxJava supports blocking operations, as much as possible this should be avoided. This is
because that instead of being data being pushed as it is ready (the reactive way), we are instead
pulling data and blocking the calling thread. In addition, using a blocking operation will cause any
exceptions to be thrown on the calling thread; so if the operation were to be invoked on the main
thread, the application would crash. When absolutely necessary though, blocking operators are a
nice way of stepping out of the reactive world.

The Lazy Approach


As mentioned earlier, RxJava was designed with laziness in mind. That is, long-running operations
should be delayed as much as possible until .subscribe() is invoked on an Observable. To make our
solution lazy we can make use of the Observable creation methods .fromCallable() or .defer().
.defer() takes in an ObservableSource which is basically a factory that returns an Observ-
able whenever the outer Observable is subscribed to. In our case, we want to return Observ-
able.fromItereable(User.getAllUsers()) whenever an Observer subscribes.

1 /**
2 * @return a list of users with blogs
3 */
4 public Observable<User> getUsersWithBlogs() {
5 return Observable.defer(() ->
6 Observable.fromIterable(UserCache.getAllUsers())
7 ).filter(user -> user.blog != null && !user.blog.isEmpty())
8 .sorted((user1, user2) -> user1.name.compareTo(user2.name));
9 }

Now that the long running operation is wrapped in a .defer(), we have full control as to what
thread this should run on simply by specifying the appropriate Scheduler in .subscribeOn() and
.observeOn().
Chapter 5: Reactive Modeling on Android 62

1 /**
2 * @return a list of users with blogs
3 */
4 public Observable<User> getUsersWithBlogs() {
5 return Observable.defer(() ->
6 Observable.fromIterable(UserCache.getAllUsers())
7 ).subscribeOn(Schedulers.io())
8 .filter(user -> user.blog != null && !user.blog.isEmpty())
9 .sorted((user1, user2) -> user1.name.compareTo(user2.name))
10 .observeOn(AndroidSchedulers.mainThread());
11 }

With this change, all subscriptions should now occur on a thread provided by Schedulers.io() and
the resulting emission will be propagated to the Android main thread. Our code is now fully reactive
and subscription should only occur at the moment the data is needed.

Reactive Everything
From the previous examples, we have seen that we can wrap any object in an Observable and jump
between non-reactive and reactive states using .blockingX() operators. In addition, we can delay
execution of an operation by wrapping it in a .fromCallable() or .defer() Observable creation
method. Using these constructs, we can start converting areas of an Android app to be reactive.

Long Operations
A good place to start using RxJava is whenever you have a process that takes a while to compute—
network calls, disk reads and writes, bitmap processing, etc. The following example illustrates a
simple function that will write text to the file system.

1 /**
2 * Writes {@code text} to the file system.
3 *
4 * @param context a Context
5 * @param filename the name of the File
6 * @param text the String of text to write
7 * @return true if the text was successfully written, otherwise, false
8 */
9 public boolean writeTextToFile(
10 Context context,
11 String filename,
12 String text
Chapter 5: Reactive Modeling on Android 63

13 ) {
14 FileOutputStream outputStream;
15 try {
16 outputStream = context.openFileOutput(
17 filename, Context.MODE_PRIVATE
18 );
19 outputStream.write(text.getBytes());
20 outputStream.close();
21 return true;
22 } catch (Exception e) {
23 e.printStackTrace();
24 return false;
25 }
26 }

When calling this function, we need to make sure that it is done off the main thread since this
operation may take a while depending on the text to be written. Imposing such restriction to the
caller adds mental load to the developer which increases the likelihood of bugs and it can potentially
slow down development. We can prevent such invocations on the main thread by perhaps adding
a comment to the function, implying that the method is synchronous in the method name, etc.
Although these changes are generally good practice, insuring that the method is called off the main
thread is still not guaranteed.
Using RxJava, we can easily wrap this into an Observable and specify the Scheduler that it should
run on. This way the caller doesn’t even need to be concerned about invoking the function in a
separate thread–the function will guarantee it.

1 /**
2 * Writes {@code text} to the filesystem.
3 *
4 * @param context a Context
5 * @param filename the name of the File
6 * @param text the String of text to write
7 * @return An Observable emitting a boolean indicating
8 * whether or not the text was successfully written.
9 */
10 public Observable<Boolean> writeTextToFile(
11 Context context,
12 String filename,
13 String text
14 ) {
15 return Observable.fromCallable(() -> {
16 FileOutputStream outputStream;
Chapter 5: Reactive Modeling on Android 64

17 outputStream = context.openFileOutput(
18 filename,
19 Context.MODE_PRIVATE
20 );
21 outputStream.write(text.getBytes());
22 outputStream.close();
23 return true;
24 }).subscribeOn(Schedulers.io());
25 }

Using .fromCallable(), writing the text to file is deferred up until subscription time. Since
exceptions are first-class objects in RxJava, one other benefit of our change is that we no longer
need to wrap the operation in a try/catch, the exception will simply be propagated downstream
rather than being swallowed. This allows the caller to handle the exception in a granular way (i.e.
show an error to the user depending on what exception was thrown).
One other optimization we can do is return a Completable rather than an Observable. A Com-
pletable is a special type of Observable–similar to a Single–that simply indicates if a computation
succeeded via .onCompleted(), or failed via .onError(). In this example, returning a Completable
makes more sense since it seems superfluous to return a single true in an Observable stream.

1 /**
2 * Writes {@code text} to the filesystem.
3 *
4 * @param context a Context
5 * @param filename the name of the File
6 * @param text the String of text to write
7 * @return A Completable
8 */
9 public Completable writeTextToFile(
10 Context context,
11 String filename,
12 String text
13 ) {
14 return Completable.fromAction(() -> {
15 FileOutputStream outputStream;
16 outputStream = context.openFileOutput(
17 filename,
18 Context.MODE_PRIVATE
19 );
20 outputStream.write(text.getBytes());
21 outputStream.close();
22 }).subscribeOn(Schedulers.io());
23 }
Chapter 5: Reactive Modeling on Android 65

To complete the operation, we use the .fromAction() operation of a Completable since the previous
return value of true is no longer needed.

Completable, Single, and Maybe


So far, the Observable class has been our focus for enabling reactive programming with RxJava.
However, RxJava also offers the following alternative base reactive types:

Single

In our previous example in Leaving the Reactive World, we have looked at another base reactive
type called a Single. As mentioned, a Single is a special type of Observable that only emits a single
item rather than a stream of items. As a consequence, an observer to a Single, a SingleObserver,
has a different signature and will only receive the following events:

• .onSubscribe(): invoked on subscription and a Disposable object is passed along which can
be used to unsubscribe from the Single
• .onSuccess(): invoked when the Single has emitted an item
• .onError(): invoked when the Single has encountered an error

1 public interface SingleObserver<T> {


2
3 void onSubscribe(Disposable d);
4
5 void onSuccess(T value);
6
7 void onError(Throwable e);
8 }

Completable

As we’ve seen in the previous example of writing text to the file system, a Completable is another
base reactive type that notifies an observer whether or not an operation succeeds. It does not emit
an item, it simply tells the observer if the operation passes or fails. An observer to a Completable, a
CompletableObserver, has the following events:

• .onSubscribe(): invoked on subscription and a Disposable object is passed along which can
be used to unsubscribe from the Completable
• .onComplete(): invoked when the Completable completes
• .onError(): invoked when the Completable has encountered an error
Chapter 5: Reactive Modeling on Android 66

1 public interface CompletableObserver<T> {


2
3 void onSubscribe(Disposable d);
4
5 void onComplete();
6
7 void onError(Throwable e);
8 }

Maybe

A Maybe can be thought of as a mix of a Single and a Completable. It is like a Single in that 1 item
may be emitted, or like a Completable in that 0 items may be emitted. Its observer, a MaybeObserver,
has the following events:

• .onSubscribe(): invoked on subscription and a Disposable object is passed along which can
be used to unsubscribe from the Maybe
• .onComplete(): invoked when the Maybe completes. This method is invoked when the Maybe
does not emit an item
• .onSuccess(T value): invoked when the Maybe emits a single item
• .onError(): invoked when the Completable has encountered an error

1 public interface MaybeObserver<T> {


2
3 void onSubscribe(Disposable d);
4
5 void onSuccess(T value);
6
7 void onComplete();
8
9 void onError(Throwable e);
10 }

Since Single, Maybe and Completable offer a subset of capabilities compared to an Observable, as
you might imagine, the operators that can be performed on them are also limited. For example, the
.toList() operator is not available on a Single or a .reduce() operator on a Completable.

Collectively, these alternative base reactive types allow you to be more specific in the type system.
While it is perfectly valid to use an Observable that only emits a single item or an Observable that
only invokes a terminal event, it is preferred to be as specific as possible as it is more expressive and
it informs the caller about the expected behavior of the underlying computation.
Chapter 5: Reactive Modeling on Android 67

If another type is required, however, say when using the operator .zip() with a Single and with
an Observable, it is possible to convert between the two types through transformational methods
(e.g. Single, Maybe and Completable have the .toObservable() method which converts the type
to an Observable). Conversely, an Observable can may be converted to another base reactive type
depending on the operator. For example, as we’ve seen in a previous example invoking .toList()
on an Observable returns a Single.

Replacing Callbacks
So far, all the examples that we’ve looked at emit either one value (i.e. can be modeled as a Single),
or tell us if an operation succeeded or failed (i.e. can be modeled as a Completable).
How might we convert areas in our app that receive continuous updates or events (e.g. location
updates, view click events, sensor events, etc.)?
We will look at two ways to do this, first by using .create(), and then by using a new construct
called Subjects.
.create() allows us to explicitly invoke any of the available methods of an Observer (i.e. .onNext(),
.onComplete() or .onError()) as we receive updates from our data source. As we’ve seen, to use
.create(), we pass in an ObservableOnSubscribe which receives an ObservableEmitter whenever
an Observer subscribes. Using the received emitter, we can then perform all the necessary set-up
calls to start receiving updates and then invoke the appropriate emitter event.
In the case of location updates, we can register to receive updates in .create() and emit location
updates as received.

1 public class LocationManager implements


2 GoogleApiClient.ConnectionCallbacks,
3 GoogleApiClient.OnConnectionFailedListener {
4
5 GoogleApiClient googleApiClient;
6
7 LocationManager(Context context) {
8 this.googleApiClient = new GoogleApiClient.Builder(context)
9 .addConnectionCallbacks(this)
10 .addOnConnectionFailedListener(this)
11 .addApi(LocationServices.API)
12 .build();
13 }
14
15 @Override public void onConnected(@Nullable Bundle bundle) {
16 // googleApiClient connected
17 }
Chapter 5: Reactive Modeling on Android 68

18
19 @Override public void onConnectionSuspended(int i) {
20 // googleApiClient suspended
21 }
22
23 @Override public void onConnectionFailed(
24 @NonNull ConnectionResult connectionResult
25 ) {
26 // googleApiClient failed to connect
27 }
28
29 /**
30 * Connects the GoogleApiClient.
31 */
32 void connect() {
33 this.googleApiClient.connect();
34 }
35
36 /**
37 * @return true if GoogleApiClient is connected, otherwise, false
38 */
39 boolean isConnected() {
40 return this.googleApiClient.isConnected();
41 }
42
43 /**
44 * Call to receive device location updates. `.connect()` must be called first.
45 * @return An Observable emitting location updates
46 */
47 Observable<Location> observeLocation() {
48 return Observable.create(emitter -> {
49
50 // Ensure GoogleApiClient is connected
51 if (!isConnected()) {
52 emitter.onError(
53 new Exception("GoogleApiClient not connected")
54 );
55 return;
56 }
57
58 // Create location request
59 LocationRequest locationRequest = new LocationRequest();
Chapter 5: Reactive Modeling on Android 69

60 locationRequest.setInterval(1000);
61 locationRequest.setPriority(
62 LocationRequest.PRIORITY_HIGH_ACCURACY
63 );
64
65 // Check location permissions
66 LocationSettingsRequest.Builder builder =
67 new LocationSettingsRequest.Builder()
68 .addLocationRequest(locationRequest);
69 PendingResult<LocationSettingsResult> pendingResult =
70 LocationServices.SettingsApi.checkLocationSettings(
71 googleApiClient,
72 builder.build()
73 );
74 pendingResult.setResultCallback(result -> {
75 Status status = result.getStatus();
76
77 switch (status.getStatusCode()) {
78 case LocationSettingsStatusCodes.SUCCESS:
79 startLocationUpdates(
80 googleApiClient,
81 emitter,
82 locationRequest
83 );
84 break;
85 case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
86 // Resolution required from user
87 break;
88 case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
89 // Location settings are not satisfied
90 break;
91 }
92 });
93 });
94 }
95
96 @SuppressWarnings({ "MissingPermission" })
97 private void startLocationUpdates(
98 GoogleApiClient googleApiClient,
99 ObservableEmitter<Location> emitter,
100 LocationRequest request
101 ) {
Chapter 5: Reactive Modeling on Android 70

102 LocationListener listener = location -> {


103 if (!emitter.isDisposed()) {
104 emitter.onNext(location);
105 }
106 };
107
108 emitter.setCancellable(() -> {
109 LocationServices.FusedLocationApi.
110 removeLocationUpdates(
111 googleApiClient,
112 listener
113 );
114 });
115 LocationServices.FusedLocationApi.requestLocationUpdates(
116 googleApiClient,
117 request,
118 listener
119 );
120 }
121 }

Above, we have created a class LocationManager wherein we can start receiving location updates
through the method .observeLocation(). Once the GoogleApiClient is deemed connected, the
function inside the .create() call first checks if location settings are satisfied, and if so, the function
will then request location updates (i.e. the method .startLocationUpdates() is invoked). When
an updated location is then received, it is emitted to the observer. In addition, we’ve also added a
Cancellable to the emitter via emitter.setCancellable(...) which ensures that we stop listening
to location updates when there are no longer any observers to the created Observable.
As we can see here, we essentially replaced the callback-style interface and instead emit the received
location in the created Observable stream.

Note in the code example above that we are not handling cases when location settings are not
satisfied (i.e. cases when RESOLUTION_REQUIRED or SETTINGS_CHANGE_UNAVAILABLE is received).
Handling these cases were left out for brevity but if you want to delve deeper in how to handle
these scenarios, consult the Android docs on receiving location updates.
https://developer.android.com/training/location/receive-location-updates.html

What might happen if multiple observers decide to subscribe to this Observable? Since .create()
returns a cold Observable, the function inside .create() would be repeated on each new subscrip-
tion which means a new location update request would be made. Clearly this is not what we want
Chapter 5: Reactive Modeling on Android 71

and instead we would like to share one subscription but have as many observers as we would like.
To accomplish this, we need a way to convert the cold Observable to a hot Observable.

Multicasting

The simplest mechanism to convert a given cold Observable to a hot Observable is by using the
method .publish(). Calling .publish() returns a ConnectableObservable which is a special type
of Observable wherein each Observer shares the same underlying resource. In other words, using
.publish(), we are able to multicast or share to multiple observers.
Subscribing to a ConnectableObservable, however, does not begin emitting items.

1 ConnectableObservable<Integer> observable = Observable.create(source -> {


2 Log.d(TAG, "Inside subscribe()");
3 for (int i = 0; i < 10; i++) {
4 source.onNext(i);
5 }
6 source.onComplete();
7 }).subscribeOn(Schedulers.io()).publish();
8
9 observable.subscribe(i -> {
10 // This will never be called
11 Log.d(TAG, "Observer 1: " + i);
12 });
13
14 observable.subscribe(i -> {
15 // This will never be called
16 Log.d(TAG, "Observer 2: " + i);
17 });

For the Observable to start emitting items, an explicit call to .connect() is required.

1 ConnectableObservable<Integer> observable = // ...


2
3 observable.connect();
4
5 // ...observers' onNext() method should now be called

.publish() is commonly paired with .refCount() which implicitly will connect the Observable as
long as there is at least one subscription (i.e. the Observable internally keeps a reference count of
observers). The .publish().refCount() combo is so common in RxJava that the operator .share()–
which is basically an alias for .publish().refCount()–was introduced.
Rewriting LocationManager to support multicasting gives us:
Chapter 5: Reactive Modeling on Android 72

1 public class LocationManager {


2
3 Observable<Location> locationObservable =
4 Observable.create(emitter -> {
5
6 // Ensure GoogleApiClient is connected
7 if (!isConnected()) {
8 emitter.onError(
9 new Exception("GoogleApiClient not connected")
10 );
11 return;
12 }
13
14 // Create location request
15 LocationRequest locationRequest = new LocationRequest();
16 locationRequest.setInterval(1000);
17 locationRequest.setPriority(
18 LocationRequest.PRIORITY_HIGH_ACCURACY
19 );
20
21 // Check location permissions
22 LocationSettingsRequest.Builder builder =
23 new LocationSettingsRequest.Builder()
24 .addLocationRequest(locationRequest);
25 PendingResult<LocationSettingsResult> pendingResult =
26 LocationServices.SettingsApi.checkLocationSettings(
27 googleApiClient,
28 builder.build()
29 );
30 pendingResult.setResultCallback(result -> {
31 Status status = result.getStatus();
32
33 switch (status.getStatusCode()) {
34 case LocationSettingsStatusCodes.SUCCESS:
35 startLocationUpdates(
36 googleApiClient,
37 emitter,
38 locationRequest
39 );
40 break;
41 default:
42 // Resolution required from user
Chapter 5: Reactive Modeling on Android 73

43 break;
44 }
45 });
46 }).share();
47
48 /**
49 * Call to receive device location updates.
50 * @return An Observable emitting location updates
51 */
52 Observable<Location> observeLocation() {
53 return locationObservable;
54 }
55 }

Simply, we have moved out the Observable creation to an instance field of LocationManager and
have turned it into a multicasted Observable via the .share() operator.

Subjects

A Subject behaves both as an Observable and as an Observer. Subjects are an alternative to


multicasting the same resource to multiple subscribers. Implementation-wise, we would want to
expose the Subject as an Observable to clients while expose it, or keep it as a Subject, to the
provider.

1 public class LocationManager {


2
3 private Subject<Location> locationSubject = PublishSubject.create();
4
5 /**
6 * Invoke this method when this LocationManager should
7 * start listening to location updates.
8 */
9 public void connect() {
10 this.googleApiClient.connect();
11 }
12
13 @Override public void onConnected(@Nullable Bundle bundle) {
14 // start listening to location updates
15 final LocationRequest locationRequest = new LocationRequest();
16 locationRequest.setInterval(1000);
17 locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
18 LocationServices.FusedLocationApi.requestLocationUpdates(
Chapter 5: Reactive Modeling on Android 74

19 googleApiClient,
20 locationRequest,
21 location -> {
22 locationSubject.onNext(location);
23 }
24 );
25 }
26
27 /**
28 * Call to receive device location updates.
29 * @return An Observable emitting location updates
30 */
31 public Observable<Location> observeLocation() {
32 return locationSubject.hide();
33 }
34 }

In this new implementation, the subtype PublishSubject is used which emits events as they arrive
starting from the time of subscription. That is, if a subscription is performed at a point when
location updates have already been emitted, past emissions will not be received by the observer,
only subsequent ones will be emitted. Also notice that the call .hide() was invoked on the Subject
which is generally what you want when exposing the Subject externally so that consumers can
only use it as an Observable and not as an Observer.
In addition to PublishSubject, RxJava has a few other varieties of Subject types:

• PublishSubject: emits to an observer only items that are emitted after the time of the
subscription
• AsyncSubject: emits to an observer only the last value after the Observable successfully
completes
• BehaviorSubject: option subscription, a BehaviorSubject will emit to an observer the most
recently emitted item and any subsequent items
• ReplaySubject: emits to an observer all previously emitted items and any subsequent items

View Events
UI events such as a Button clicks or changes in an EditText are another good place to use RxJava.
An open source library, RxBinding¹³ (developed by Jake Wharton), provides the necessary bindings
to turn View events into Observable streams.
Using RxBinding, you can turn View click events into an Observable.

¹³https://github.com/JakeWharton/RxBinding
Chapter 5: Reactive Modeling on Android 75

1 Observable<Object> clicks = RxView.clicks(view);


2 clicks.subscribe(obj -> {
3 // Get click events here
4 });

This example is quite trivial but the benefits of using Rxjava become apparent when used in
conjunction with operators. Say for example we wanted to detect double clicks (i.e. 2 clicks that
happen within 300 milliseconds apart).

1 Observable<Object> clicks = RxView.clicks(view);


2
3 Observable<List<Object>> clickAggregate =
4 clicks.buffer(300, TimeUnit.MILLISECONDS);
5
6 Observable<List<Object>> doubleClicks =
7 clickAggregate.filter(list -> list.size() >= 2);
8
9 doubleClicks.subscribe(o -> {
10 Timber.d("Received double clicks.");
11 });

Normally the above method calls to the click Observable would be chained, but for educational
purposes I’ve separated it out line-by-line so we can understand the transformations at each step.
First, we convert click events from view to an Observable using RxView.clicks(). After that, we
use the operator .buffer() which buffers items that occur within a provided timespan–in this case
300 milliseconds–into a List<Object>. Afterwards, we simple filter each emission of the .buffer()
operation using .filter() to check if the buffered list contains 2 or more items, if it does, then a
double click was just performed.
We will look into the .buffer() operator more in Chapter 6: Buffering.

Disposable and the Activity/Fragment Lifecycle


So far we have overlooked a key component in a reactive stream–the Disposable. A Disposable
is returned as a result from a subscription so that we can control when to unsubscribe so that the
underlying Observable can stop emitting events. Failure to do so can cause unwanted memory leaks
that are hard to trace.
When dealing with the Activity/Fragment lifecycle, a good place to unsubscribe would be when the
Activity or Fragment is no longer needed. That is, in the .onDestroy() lifecycle.
Chapter 5: Reactive Modeling on Android 76

1 public class MyActivity extends Activity {


2 Disposable disposable;
3
4 protected void onCreate(Bundle savedInstanceState) {
5 this.disposable = // ...subscribe to some Observable
6 }
7
8 protected void onDestroy() {
9 if (!disposable.isDisposed()) {
10 disposable.dispose();
11 }
12 }
13 }

RxJava also has classes that implement DisposableContainer, such as CompositeDisposable, to


make disposing from multiple Disposable instances easy.

1 public class MyActivity extends Activity {


2 CompositeDiposable disposables = new CompositeDisposable();
3
4 protected void onCreate(Bundle savedInstanceState) {
5 Disposable disposable1 = // ...subscribe to some Observable
6 Disposable disposable2 = // ...subscribe to another Observable
7 disposables.addAll(disposable1, disposable2);
8 }
9
10 protected void onDestroy() {
11 if (!disposables.isDisposed()) {
12 disposables.dispose();
13 }
14 }
15 }

In general, unsubscribing from Disposables in an Activity/Fragment .onDestroy() method is a


good guideline however, ideally unsubscribing should be done as soon as a resource is no longer
needed. For example, say an Observable’s events is only needed when an Activity is in the
foreground. In this case, subscription should occur on the Activity’s .onResume() method and
unsubscription should occur in the opposing lifecycle method–.onPause().
Chapter 5: Reactive Modeling on Android 77

RxLifecycle
Alternatively, an open source library called RxLifecycle¹⁴, created by Trello, can be used to
automatically unsubscribe from an Observable once an Activity/Fragment lifecycle event occurs.
This way, you don’t have to manage the Disposable object explicitly, RxLifecycle will handle it for
you.
To bind a Disposable with RxLifecycle, you can specify a lifecycle event when an Observable should
be unsubscribed (e.g. on an Activity’s .onDestroy()):

1 observable
2 .compose(RxLifecycle.bindUntilEvent(
3 lifecycle,
4 ActivityEvent.DESTROY
5 ))
6 .subscribe();

Or you can let RxLifecycle decide when it should unsubscribe from an Observable. In this case,
it will unsubscribe at the opposing lifecycle event from when the Observable was subscribed (i.e.
.onCreate()/.onDestroy(), .onStart()/.onStop() or .onResume()/.onPause()).

1 observable
2 .compose(
3 RxLifecycleAndroid.bindActivity(lifecycle)
4 )
5 .subscribe();

In both examples, lifecycle represents an Observable<ActivityEvent> which can be obtained by


subclassing RxActivity/RxFragment:

1 public class MyActivity extends RxActivity {


2 @Override
3 protected void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 observable
6 .compose(RxLifecycle.bindUntilEvent(
7 lifecycle,
8 ActivityEvent.DESTROY
9 ))
10 .subscribe();
11 }
12 }

Or alternatively, you can also create an Observable<ActivityEvent> yourself:


¹⁴https://github.com/trello/RxLifecycle
Chapter 5: Reactive Modeling on Android 78

1 public class MyActivity extends Activity {


2 private BehaviorSubject<ActivityEvent> lifecycleSubject =
3 BehaviorSubject.create();
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 lifecycleSubject.onNext(ActivityEvent.CREATE);
9 observable
10 .compose(RxLifecycle.bindUntilEvent(
11 lifecycle,
12 ActivityEvent.DESTROY
13 ))
14 .subscribe();
15 }
16
17 @Override
18 protected void onStart() {
19 super.onStart();
20 lifecycleSubject.onNext(ActivityEvent.START);
21 }
22
23 @Override
24 protected void onResume() {
25 super.onResume();
26 lifecycleSubject.onNext(ActivityEvent.RESUME);
27 }
28
29 @Override
30 protected void onPause() {
31 lifecycleSubject.onNext(ActivityEvent.PAUSE);
32 super.onPause();
33 }
34
35 @Override
36 protected void onStop() {
37 lifecycleSubject.onNext(ActivityEvent.STOP);
38 super.onStop();
39 }
40
41 @Override
42 protected void onDestroy() {
Chapter 5: Reactive Modeling on Android 79

43 lifecycleSubject.onNext(ActivityEvent.DESTROY);
44 super.onDestroy();
45 }
46 }

In addition, RxLifecycle can also be used in conjunction with the new Lifecycle class in the Android
Architecture Components¹⁵ library:

1 public class MyActivity extends LifecycleActivity {


2 private LifecycleProvider<Lifecycle.Event> provider =
3 AndroidLifecycle.createLifecycleProvider(this);
4
5 @Override
6 protected void onCreate() {
7 super.onCreate();
8 myObservable
9 .compose(provider.bindToLifecycle())
10 .subscribe();
11 }
12 }

¹⁵https://developer.android.com/topic/libraries/architecture/lifecycle.html
Chapter 6: Backpressure
By now, you should be familiar with the distinction of push vs pull in reactive interfaces. Instead of
the traditional model of requesting data from a source (i.e. pulling data), the source will push data to
an observer as the data is ready (See Chapter 2: Push vs Pull). One problem we overlooked though
is: what happens if a consumer can’t keep up with a producer? That is, what happens if a producer
(Observable) produces data faster than a consumer (Observer or an Operator) can consume? As you
might expect, this situation puts pressure on the system and can cause bugs if handled incorrectly.
In this chapter, we will dive deeper into this problem and look into different ways to solve it.

Fast Producer, Slow Consumer


Say given a list of image files, we were to load each image file to memory and apply a CPU-bound
function .processBitmap() which takes some time to compute.

1 File[] imageFiles = // image files to process


2
3 Observable<File> fileStream = Observable.fromArray(
4 imageFiles
5 ).subscribeOn(Schedulers.computation());
6
7 Observable<Bitmap> bitmapStream =
8 fileStream.map(file -> BitmapFactory.decodeFile(file.getAbsolutePath()));
9
10 Observable<Pair<Bitmap, Integer>> bitmapZippedStream = Observable.zip(
11 bitmapStream,
12 Observable.range(1, imageFiles.length),
13 Pair::new
14 ).doOnNext(pair -> Log.d(TAG, "Produced bitmap: " + pair.second));
15
16 bitmapZippedStream.observeOn(
17 AndroidSchedulers.mainThread()
18 ).subscribe(pair -> {
19 processBitmap(pair.first);
20 Log.d(TAG, "Processed bitmap: " + pair.second);
21 });
Chapter 6: Backpressure 81

1 private void processBitmap(Bitmap bitmap) {


2 // Simulate long operation
3 try {
4 new Thread(() -> {
5 }).sleep(300);
6 } catch (InterruptedException e) {
7 e.printStackTrace();
8 }
9 return bitmap;
10 }

The above code should be fairly straightforward: first, a list of image files are converted into an
Observable<File>. Using .map(), each emission from that stream is then decoded into a bitmap
which produces an Observable<Bitmap>. The bitmap stream is then zipped with an integer stream
(i.e. Observable.range(1, imageFiles.length)) and combined as a Pair. Each decoded bitmap is
then printed on Logcat. Finally, in the .subscribe() function, each bitmap is processed via a long
operation .processBitmap() (a thread sleep of 300 milliseconds is performed to simulate a this).
Can you guess what running the above code might produce?
Given a sufficiently long list of large images (1-5 Mb), the above code may throw an OutOfMemo-
ryError (in RxJava 1.x, the above code would have produced a MissingBackpressureException,
however, this was changed since RxJava 2.x). The reason for this is because the producer will
continue to emit bitmaps despite the consumer not being able to keep up with the emissions. In
turn, the emitting Observable maintains an internal unbounded buffer of the generated bitmaps
and if the consumer cannot keep up, the buffer will continue to grow until the program runs out of
memory. To solve this, we need a way to notify upstream that it should slow down its production
until the consumer downstream can keep up with processing items.

Backpressure
The mechanism by which we can notify upstream that it should slow down its production is called
backpressure. Using an Observable however, we cannot apply backpressure as Observables are not
designed to support backpressure. For this, we will need another base reactive class called Flowable.

Flowable
In a word, Flowable is a base reactive class that is backpressure-enabled. If you know you are dealing
with a stream that you might want to add backpressure to, a Flowable is what you want. Flowable
supports the following backpressure strategies:

• BackpressureStrategy.ERROR - produces a MissingBackpressureException in the case


when downstream cannot keep up with item emissions
Chapter 6: Backpressure 82

• BackpressureStrategy.BUFFER - buffers all items until downstream consumes it (default


buffer size is 128)
• BackpressureStrategy.DROP - drops the most recent item if downstream cannot keep up
• BackpressureStrategy.LATEST - keeps only the latest item overwriting any previous value
if downstream cannot keep up
• BackpressureStrategy.MISSING - no backpressure is added to the Flowable (this is equiva-
lent to using an Observable)

So when might you want to choose a Flowable over an Observable? The RxJava wiki¹⁶, offers the
following general guidelines:

When to use Observable

• You have a flow of no more than 1000 elements at its longest: i.e., you have so few
elements over time that there is practically no chance for OOME (OutOfMemory-
Error) in your application.
• You deal with GUI events such as mouse moves or touch events: these can rarely
be backpressured reasonably and aren’t that frequent. You may be able to handle
an element frequency of 1000 Hz or less with Observable but consider using
sampling/debouncing anyway.
• Your flow is essentially synchronous but your platform doesn’t support Java Streams
or you miss features from it. Using Observable has lower overhead in general than
Flowable. (You could also consider IxJava which is optimized for Iterable flows
supporting Java 6+).

When to use Flowable

• Dealing with 10k+ of elements that are generated in some fashion somewhere and
thus the chain can tell the source to limit the amount it generates.
• Reading (parsing) files from disk is inherently blocking and pull-based which works
well with backpressure as you control, for example, how many lines you read from
this for a specified request amount).
• Reading from a database through JDBC is also blocking and pull-based and is
controlled by you by calling ResultSet.next() for likely each downstream request.
• Network (Streaming) IO where either the network helps or the protocol used
supports requesting some logical amount.
• Many blocking and/or pull-based data sources which may eventually get a non-
blocking reactive API/driver in the future.

Rewriting our example using backpressure with Flowable gives us:


¹⁶https://github.com/ReactiveX/RxJava/wiki/What’s-different-in-2.0
Chapter 6: Backpressure 83

1 File[] imageFiles = // image files to process


2
3 Flowable<File> fileStream = Flowable.fromArray(
4 imageFiles
5 ).subscribeOn(Schedulers.computation());
6
7 Flowable<Bitmap> bitmapStream =
8 fileStream.map(file -> BitmapFactory.decodeFile(file.getAbsolutePath()));
9
10 Flowable<Pair<Bitmap, Integer>> bitmapZippedStream = Flowable.zip(
11 bitmapStream,
12 Flowable.range(1, imageFiles.length),
13 Pair::new
14 ).doOnNext(pair -> Log.d(TAG, "Produced bitmap: " + pair.second));
15
16 bitmapZippedStream.observeOn(
17 AndroidSchedulers.mainThread()
18 ).subscribe(pair -> {
19 processBitmap(pair.first);
20 Log.d(TAG, "Processed bitmap: " + pair.second);
21 });

With this change, we replaced all references of Observable to Flowable. By default, the backpressure
strategy used by Flowable is to impose a bounded buffer–the buffer is filled by the producer and
production will halt until most items in the buffer are consumed by the consumer. It may still be the
case, however, that the above code would produce an OutOfMemoryError. This is because the default
buffer size is set to be 128 items and depending on your use-case, that size might be too much. To
mitigate this, we can specify a different buffer capacity in an overloaded version of .observeOn()

1 // ...
2 int bufferSize = 10;
3 bitmapZippedStream.observeOn(
4 AndroidSchedulers.mainThread(),
5 false,
6 bufferSize
7 ).subscribe(pair -> {
8 // ...
9 });

Here we have changed the bounded buffer size to only contain 10 items. The second parameter to
.observeOn() indicates whether or not an .onError() notification should cut ahead of .onNext()
notifications, in this case, specifying false indicates that it can. Running the above code with
backpressure should print out:
Chapter 6: Backpressure 84

1 Produced bitmap: 1
2 Produced bitmap: 2
3 ...
4 Produced bitmap: 10
5 Processed bitmap: 1
6 Processed bitmap: 2
7 ...
8 Processed bitmap: 7
9 Processed bitmap: 8
10 Produced bitmap: 11
11 ...

As you can see, production of bitmaps halted once the set buffer size of 10 has been reached. The
consumer was then allowed to catch up and production continued when the buffer was close to
empty (in this case, production continued once the buffer size contained 2 items).

Backpressure using Subscriber


Fine-grained control of how a consumer notifies a producer that it can consume more data
can be done by using a Subscriber. In addition to the standard observer methods .onNext(T),
.onError(Throwable), and .onComplete(), a Subscriber has an additional method, .onSub-
scribe(Subscription), which is called upon subscribing to a producer (i.e. Flowable). The Sub-
scription object received from .onSubscribe(Subscription) is then used to control the flow of
production from the producer through its method .request(long). As soon as .onSubscribe()
is invoked, we must immediately request data from the producer via .request(long) to begin
receiving items.

1 int bufferSize = 10;


2 bitmapZippedStream.observeOn(
3 AndroidSchedulers.mainThread(),
4 false,
5 bufferSize
6 ).subscribe(new Subscriber<Pair<Bitmap, Integer>>() {
7
8 Subscription subscription;
9
10 @Override
11 public void onSubscribe(Subscription s) {
12 subscription = s;
13 subscription.request(1);
14 }
15
Chapter 6: Backpressure 85

16 @Override
17 public void onNext(Pair<Bitmap, Integer> pair) {
18 // Do something with `pair`
19 subscription.request(1);
20 }
21
22 @Override
23 public void onError(Throwable throwable) {
24 }
25
26 @Override
27 public void onComplete() {
28 }
29 });

Above, we request 1 item to be produced as soon as the Subscriber is subscribed. Afterwards, for
each .onNext() item, we request 1 more item to be produced. There’s nothing very special here and
it essentially behaves the same way as before. If however our consumption of data should be limited
and we want to communicate this to the producer (e.g. say we were caching the bitmaps and we
want to stop receiving them when the cache is full) we can do that by conditionally requesting from
the Subscription object in .onNext().

1 .subscribe(new Subscriber<Pair<Bitmap, Integer>>() {


2 // ...
3 @Override
4 public void onNext(Pair<Bitmap, Integer> pair) {
5 // Do something with `pair`
6 if (shouldReceiveMoreBitmaps()) {
7 subscription.request(1);
8 }
9 }
10 // ...
11 });

Throttling and Buffering Items


In addition to backpressure, there are several handy operators that can be used to solve the problem
of a fast producer but a slow consumer. These operators allow you to either throttle or buffer items
so that a consumer can keep up. Oftentimes, these operators are preferred over backpressure as they
are much simpler to work with.
Chapter 6: Backpressure 86

Throttling
Let’s look at an Android-specific example where we might want to apply these principles–a device’s
accelerometer events. First, let’s create a class called DeviceSensorManager that can be queried for
an Observable that emits accelerometer events.

1 public class DeviceSensorManager {


2
3 private Observable<SensorEvent> accelerometerEventObservable;
4
5 public DeviceSensorManager(Context context) {
6 accelerometerEventObservable =
7 Observable.create(emitter -> {
8 SensorEventListener sensorEventListener =
9 new SensorEventListener() {
10
11 @Override public void onSensorChanged(SensorEvent e) {
12 if (e.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
13 emitter.onNext(e);
14 }
15 }
16
17 @Override public void onAccuracyChanged(
18 Sensor sensor,
19 int accuracy
20 ) { }
21 };
22
23 SensorManager sensorManager =
24 (SensorManager) context.getSystemService(
25 Context.SENSOR_SERVICE
26 );
27 sensorManager.registerListener(
28 sensorEventListener,
29 sensorManager.getDefaultSensor(
30 Sensor.TYPE_ACCELEROMETER
31 ),
32 SensorManager.SENSOR_DELAY_NORMAL
33 );
34
35 // Clean up when there are no longer any subscribers
36 emitter.setCancellable(() -> {
37 sensorManager.unregisterListener(
Chapter 6: Backpressure 87

38 sensorEventListener
39 );
40 });
41 }
42 }).share();
43 }
44
45 public Observable<SensorEvent> accelerometerEventObservable() {
46 return accelerometerEventObservable;
47 }
48 }

When creating a DeviceSensorManager, we pass it a Context so that we can obtain a handle


to a SensorManager. Given the SensorManager, we then set a SensorEventListener that listens
for accelerometer events (i.e. events of type Sensor.TYPE_ACCELEROMETER) at a rate defined by
SensorManager.SENSOR_DELAY_NORMAL. This listener is then wrapped in an Observable and all
accelerometer events are emitted down the Observable stream. Lastly, the Observable is multicasted
using .share() so that multiple SensorEventListeners are not registered on each subscription.
The listener is also unregistered from the SensorManager when there are no longer any subscribers
(i.e. the lambda inside emitter.setCancellable(...) will be invoked when all observers of the
Observable are unsubscribed/disposed).

The rate at which accelerometer events are emitted is defined by SensorManager.SENSOR_DELAY_-


NORMAL (i.e. ∼20 milliseconds). But say for our needs we wanted to consume events at a much slower
rate; how might we do that? Surely, we can attach a separate listener with the desired rate but what
if we want to use the same Observable? There are a couple of options to achieve this, one of which
is to use the filtering operator .sample().

Sample & Throttle

.sample(long, TimeUnit) works by periodically sampling events at a specified rate by emitting the
latest item in a period while dropping all other items.
Chapter 6: Backpressure 88

Marble diagram of .sample()

.throttleFirst() and .throttleLast() on the other hand can be used to only emit the first or last
item, respectively, over a sequential time period.

Marble diagram of .throttleFirst()


Chapter 6: Backpressure 89

Marble diagram of .throttleLast()

Buffering
Another strategy to help mitigate problems with chatty producers is to buffer or collect emissions
and emit the result downstream at a less frequent rate. Two useful operators for achieving this are
.buffer() and .window().

Buffer & Window

As the name implies, .buffer(...) allows you to buffer emissions from upstream into a list.
.buffer() is overloaded to support buffering given different criteria, a few handy ones are:

• Observable.buffer(int count): buffers items count items


• Observable.buffer(ObservableSource<Type> boundary): buffers items in between emis-
sions from boundary
• Observable.buffer(long timespan, TimeUnit timeUnit): buffers items that are emitted in a
given timespan
Chapter 6: Backpressure 90

Marble diagram of .buffer()

A similar operator to .buffer(), .window(), allows you to emit Observables instead of lists.
.window() is also overloaded and allows buffers given different criteria.

Marble diagram of .window()

Why might you want a stream of Observables instead of lists? It’s helpful to think of this difference
in terms of the difference between .map() and .flatMap() as we’ve seen in Chapter 3 (See Chapter 3:
.flatMap()). With a stream of Observables, we can further chain operators and even add concurrency
(See Chapter 4: Concurrency with .flatMap()).
Chapter 7: Error Handling
In Java, when an error occurs in the normal flow of a program, an Exception is thrown. A try/catch
statement can then be used to recover from the Exception and perform the appropriate fallback
behavior (i.e. ignore the error and continue, retry the operation, display an error message to the user
etc.). Most Exceptions that are handled in this manner are checked exceptions, that is, the thrown
Exception needs to be declared and explicitly handled for our code to compile. Unchecked exceptions
however, are harder to catch and if not handled, can cause our application to crash. Oftentimes, this
is not the behavior that we want since we want apps to be perform well despite these edge cases.
In RxJava, errors are treated slightly different. Rather than being seen as exceptions from the normal
flow of a program, errors are considered to be a part of the normal flow of the program and thus
should be accounted for when dealing with a given stream. In this chapter, we will look at different
ways of handling errors in an Observable to help create resilient applications.

Errors Along the Chain


As we’ve seen earlier, one of the events an Observer can receive is the .onError(Throwable) event.
.onError() is considered a terminal such that once triggered, the Observable will no longer emit
any other event. There are several ways to invoke the .onError() notification, some are explicit
such as invoking the .onError() on an Emitter:

1 Observable<Integer> observable = Observable.create(emitter -> {


2 emitter.onError(new Exception("An error occurred."));
3 });
4 observable.subscribe(i -> {
5 }, throwable -> {
6 Log.e(TAG, "onError(): " + throwable.getMessage());
7 });

Or by returning an Observable.error() wherever an Observable is expected such as in the


.flatMap() operator:
Chapter 7: Error Handling 92

1 Observable<Integer> observable =
2 Observable.range(0, 10).flatMap(i -> {
3 return (i == 3)
4 ? Observable.error(new Exception("An error occurred"))
5 : Observable.just(i);
6 });
7 observable.subscribe(i -> {
8 }, throwable -> {
9 Log.e(TAG, "onError(): " + throwable.getMessage());
10 });

In addition to these approaches, Exceptions are also propagated to the observer whenever they are
thrown in a function contained within the Observable sequence. As one might notice, all methods
in interfaces in the io.reactivex.functions.* are defined to throw an Exception. The reason being
is that these functions are invoked in a try/catch statement internally so that when an error is
encountered, that error is propagated to the observer.

1 Observable<Integer> observable =
2 Observable.range(0, 10).map(i -> {
3 if (i == 3) {
4 throw new Exception("An error occurred.");
5 }
6 return i * 2;
7 });
8 observable.subscribe(i -> {
9 }, throwable -> {
10 Log.e("onError(): " + throwable.getMessage());
11 });

There are some Exceptions, however, that are too fatal to recover from and are not propagated down
to the observer (i.e. instances of the following classes: VirtualMachineError, ThreadDeath, and
LinkageError). Instead, these Exceptions are thrown from the thread where the Exception occurred.
Chapter 7: Error Handling 93

1 Observable<Integer> observable =
2 Observable.range(0, 10).subscribeOn(
3 Schedulers.io()
4 ).map(i -> {
5 if (i == 3) {
6 throw new OutOfMemoryError();
7 }
8 return i * 2;
9 });
10
11 observable.observeOn(
12 Schedulers.computation()
13 ).subscribe(i -> {
14 }, throwable -> {
15 Log.e("onError(): " + throwable.getMessage());
16 });

In the above code, the OutOfMemoryError won’t be captured in the .onError() call since OOMs are
considered fatal. Instead, the Exception will be thrown on a thread from Schedulers.io().

Delivering Errors
As we’ve seen, when an error is encountered in a stream, RxJava will deliver the error to the
Observer via .onError(). Given that .onError() is terminal, no further processing will occur. This
however can be problematic as Dan Lew explains in his blog post “Error Handling in RxJava”¹⁷:

I want to clear up something that many RxJava beginners get wrong: onError is an
extreme event that should be reserved for times when sequences cannot continue. It
means that there was a problem in processing the current item such that no future
processing of any items can occur.
It’s the Rx version of try-catch: it skips all code between the exception and onError.
Sometimes you want this behavior: suppose you’re downloading data then saving it to
the disk. If the download fails, you want to skip saving. But what about if you’re, say,
polling data from a source? If one poll fails you still want to continue polling. Or maybe,
in the previous example, you want to save dummy data in the case that the download
fails.
In other words: often times, instead of calling onError and skipping code, you actually
want to call onNext with an error state. It’s much easier to handle problems in onNext
since you still get to run all your code and the stream isn’t terminated.
¹⁷http://blog.danlew.net/2015/12/08/error-handling-in-rxjava/
Chapter 7: Error Handling 94

Indeed, depending on what we are processing, we might want to handle an error differently. In
the next section, we will look at the different error-handling related operators that are available in
RxJava.

Error-Handling Operators
Say we were to implement an image store such that when a request comes in it will first check if
the image is cached, and if so, return the image from the cache, otherwise, return fetch image over
the network.

1 public class ImageStore {


2
3 private ImageStoreCache cache = new ImageStoreCache();
4
5 public Observable<Bitmap> getImage(String filename) {
6 return cache.getImage(filename);
7 }
8 }
9
10 public class ImageStoreCache {
11
12 private LruCache<String, Bitmap> cache = new LruCache<>(100);
13
14 public Observable<Bitmap> getImage(String filename) {
15 return Observable.fromCallable(() -> {
16 Bitmap cachedBitmap = cache.get(filename);
17 if (cachedBitmap != null) {
18 return cachedBitmap;
19 }
20 throw new ImageNotInCacheException();
21 });
22 }
23
24
25 public void addImage(String filename, Bitmap bitmap) {
26 cache.put(filename, bitmap);
27 }
28 }
29
30 public class ImageNotInCacheException extends Exception {
31 }
Chapter 7: Error Handling 95

ImageStore so far will simply request the image from the ImageStoreCache and will not yet make
a network call if an image does not exist in the cache. Instead, it will return the ImageNotInCache-
Exception to the Observer’s .onError() method. To handle the case of fetching an image over the
network, we can make use of any of the following error-handling operators:

Observable.onErrorReturnItem(), Observable.onErrorReturn()
and Observable.onErrorResumeNext()
• Observable.onErrorReturnItem(T item): when an error is received upstream, this operator
will return the item provided to it downstream instead of the received error.

Marble diagram of .onErrorReturnItem()

• Observable.onErrorReturn(Function<? super Throwable, ? extends T> valueSupplier):


when an error is received upstream, this operator will invoke the function provided and return
the result of that function downstream instead of the received error. This operator is preferred
if you want to return a different item depending on the error.
Chapter 7: Error Handling 96

Marble diagram of .onErrorReturn()

• Observable.onErrorResumeNext(ObservableSource<? extends T> next)): similar to .on-


ErrorReturnItem() but instead of returning an item, it will pass control to the provided
Observable instead of passing the received error.

Marble diagram of .onErrorResumeNext()

In our case, we will make use of .onErrorResumeNext() to return an Observable when an


ImageNotInCacheException error is received.
Chapter 7: Error Handling 97

1 public class NetworkClient {


2 Observable<Bitmap> fetchImage(String filename) {
3 // Network call to fetch image here
4 }
5 }
6
7 public class ImageStore {
8
9 private NetworkClient networkClient;
10 private ImageStoreCache cache = new ImageStoreCache();
11
12 public ImageStore(NetworkClient networkClient) {
13 this.networkClient = networkClient;
14 }
15
16 public Observable<Bitmap> getImage(String filename) {
17 return cache.getImage(filename)
18 .onErrorResumeNext(
19 networkClient.fetchImage(
20 filename
21 ).doOnNext(bitmap -> cache.addImage(filename, bitmap))
22 );
23 }
24 }

When an error is received from the cache, we retrieve an image over the network via .fetchImage().
Finally, once the image is retrieved over the network, the cache is then updated to store the retrieved
bitmap.

Retry Operators
There are some operations that if they fail to complete require retrying either immediately or at
a later point in time. Say for example we are developing a chat application and a user sends a
message to another user. If sending that message fails because of a bad network connection, that
message should get resent at a better point in time (e.g. when the sender establishes a better network
connection). While there are many ways to solve this problem, a simple solution would be to add
retry logic until the operation succeeds.
Chapter 7: Error Handling 98

1 public class Message {


2 private String sender;
3 private String receiver;
4 private String text;
5
6 public Message(String sender, String receiver, String text) {
7 this.sender = sender;
8 this.receiver = receiver;
9 this.text = text;
10 }
11 }
12
13 public class NetworkClient {
14
15 Observable<Message> sendMessage(Message message) {
16 // Send message network call here
17 }
18 }

Above, we have a simple Message POJO that contains some text as well as the sender and the receiver
of the message. In addition, we’ve added a method in NetworkClient to send a Message to the
receiver which returns an Observable<Message> that emits the sent message to the observer if the
network call succeeds, otherwise, it emits an error.

1 Message message = new Message("chris, "angus", "Yo");


2 networkClient.sendMessage(message).subscribe(() -> {
3 // Message sending succeeds
4 }, throwable -> {
5 // Message sending fails
6 });

Observable.retry()
A straightforward approach to retry a failed operation is to use .retry(). .retry() will intercept
error notifications received upstream and not pass those through its observers. Instead, it will
resubscribe to the source Observable and give it the opportunity to complete its sequence without
error.
Chapter 7: Error Handling 99

Marble diagram of .retry()

1 Message message = new Message("chris, "angus", "Yo");


2 networkClient.sendMessage(message).retry(10).subscribe(() -> {
3 // Message sending succeeds
4 }, throwable -> {
5 // Message sending fails
6 });

Above, we have modified sending a message to retry at most 10 times until it succeeds.
It might also be useful to inspect the error before blindly retrying the operation. For example, say
the error returned is because the user that is trying to send a message is no longer authenticated. In
this case, we do not want to retry the operation but instead report the error to the observer. To do
this, we can use an overloaded version of .retry() which allows us to pass a predicate to inspect
the error to retry conditionally.

1 networkClient.sendMessage(message).retry(10, error -> {


2 return !(error instanceof AuthenticationError);
3 }).subscribe(() -> {
4 // Message sending succeeds
5 }, throwable -> {
6 // Message sending fails
7 });

While retrying an operation immediately after failure a number of times may be sufficient in some
cases, in others cases such as network issues, retrying immediately can exacerbate the issue and a
different approach for retrying is necessary.
Chapter 7: Error Handling 100

Observable.retryWhen(Function<? super
Observable<Throwable>, ? extends ObservableSource<?>>
handler)
One common way of retrying when it comes to networking issues is to use exponential backoff with
the rate of retries. That is, the delay of a subsequent retry would be some multiple of the delay of
the previous one. To do this, we can make use of .retryWhen().

Marble diagram of .retryWhen()

Using .retryWhen(), we provide it a function handler that receives errors in the form of an
Observable<Throwable> and the handler in turn would return an Observable<?>. The emission
value of the returned Observable is ignored–hence the wildcard–the operator only cares about the
.onNext() notification event which signals when the retry should be performed.

1 Observable<Message> sendMessageObservable = networkClient.sendMessage(message);


2
3 sendMessageObservable.retryWhen(throwable -> {
4 Observable<Long> retrySignal =
5 throwable.zipWith(Observable.range(0, 6), (t, i) -> i).flatMap(i -> {
6 final long delay = (long) Math.pow(2, i);
7 Log.d(TAG, "Retry delayed by: " + delay);
8 return Observable.timer(delay, TimeUnit.SECONDS);
9 });
Chapter 7: Error Handling 101

10 return retrySignal;
11 }).subscribe(m -> {
12 Log.d(TAG, "Message sent!");
13 }, throwable -> {
14 Log.d(TAG, "Failed to send message.");
15 });

Let’s break this down step-by-step:


When the message fails to send, the handler inside .retryWhen() would be invoked with an
Observable<Throwable>. That Observable is then zipped with Observable.range(0, 6) and the
zipper function (i.e. (t, i) -> i) provided will simply ignore the Throwable and instead emit a
Long. Using the emitted Long values, a transformation via .flatMap() is performed to transform
Long instances into Observable.timer() instances. Each Observable.timer() contains a delay that
is 2ˆi seconds, where i is the Long value emitted upstream, which then signals when resubscription
should occur on sendMessageObservable.
In short, we have implemented an exponential backoff retry mechanism where reattempting to
send a message will be done at most 6 times with delay increments of 1, 2, 4, 8, 16, 32 seconds. If
the message continues to fail even after 6 retries, only then would the Observer’s .onError() be
invoked.
The print statements in Logcat should display (assuming sending a message continues to fail).

1 Retrying... delayed by: 1


2 Retrying... delayed by: 2
3 Retrying... delayed by: 4
4 Retrying... delayed by: 8
5 Retrying... delayed by: 16
6 Retrying... delayed by: 32
7 Failed to send message.

Undelivered Errors
There are some cases where errors might be considered as undelivered. For example, if an Exception
occurs but no explicit .onError() handling was provided on subscription or if .onError() was
provided but the subscription has been cancelled/disposed. In these scenarios, RxJava tries to do its
best to make sure that errors are not lost or swallowed, but instead are reported in a reasonable
manner.

Handling Undelivered Errors


RxJavaPlugins.onError() is invoked in RxJava internals to handle undelivered error. Essentially,
this default .onError() behaves as you would expect if the error occurred outside of the context of
Chapter 7: Error Handling 102

RxJava–the error’s stack trace is printed out and handling is delegated to the UncaughtException-
Handler of the Thread where the error occurred.

Alternatively, a default error notification consumer can also be provided to handle undelivered errors
via RxJavaPlugins.setErrorHandler(Consumer<Throwable>). Doing so sets a static variable within
RxJava so that undelivered errors would be propagated to the provided handler as opposed to using
RxjavaPlugins.onError(). This approach is preferred as you can pipe the error into your app’s
logging module.

1 RxJavaPlugins.setErrorHandler(throwable -> {
2 Log.e("MyApp", "Received undelivered error: " + throwable.getMessage());
3 // ...
4 });

In addition, if the error occurred on the main thread and a handler was not provided in RxJavaPlu-
gins.setErrorHandler(), the default behavior of the main thread’s UncaughtExceptionHandler is
to crash the app. By providing a custom handler, this situation can be mitigated.
Bibliography
Anup Cowkur. “Functional Programming for Android Developers–Part 1.” freeCodeCamp. https://
medium.freecodecamp.com/functional-programming-for-android-developers-part-1-a58d40d6e742
Dan Lew. “Multicasting in RxJava.” Dan Lew Codes. http://blog.danlew.net/2016/06/13/multicasting-
in-rxjava/
Dan Lew. “Don’t break the chain: Use RxJava’s compose() operator.” Dan Lew Codes. http://blog.
danlew.net/2015/03/02/dont-break-the-chain/
Dan Lew. “Error Handling in RxJava.” Dan Lew Codes. http://blog.danlew.net/2015/12/08/error-
handling-in-rxjava/
David Karnok. “Backpressure.” Stack Overflow. http://stackoverflow.com/documentation/rx-java/
2341/backpressure/7701/introduction#t=201705032347091109595
David Karnok. “SubscribeOn and ObserveOn.” Advanced Reactive Java. http://akarnokd.blogspot.
com/2016/03/subscribeon-and-observeon.html
Ray Ozzie. “The Internet Services Disruption.” http://scripting.com/disruption/ozzie/TheInternetServicesDisruptio.
htm
ReactiveX. ReactiveX Wiki. http://reactivex.io/
RxAndroid. RxJava bindings for Android. https://github.com/ReactiveX/RxAndroid
RxBinding. RxJava binding APIs for Android’s UI widgets. https://github.com/JakeWharton/RxBinding
Rx team. “Rx Design Guidelines.” https://blogs.msdn.microsoft.com/rxteam/2010/10/28/rx-design-
guidelines/
RxJava. RxJava Wiki. https://github.com/ReactiveX/RxJava/wiki
Sameer Dhakal. “Howdy RxJava.” Fuzz. https://medium.com/fuzz/howdy-rxjava-8f40fef88181
Tomasz Nurkiewickz and Ben Christensen. Reactive Programming with RxJava: Creating Asyn-
chronous, Event-Based Applications. California: O’Reilly Media, 2016

You might also like