Why I’m Excited For RxJava 2.0

An Android Developer’s Perspective

Matthew Potter
jtribe

--

I’m an Android developer. So as an Android developer tends to do, I use a lot of RxJava throughout all layers of an app; from debouncing button presses to handling network calls. It provides me with a uniform, universal API, with the side-effect of allowing me to avoid the dozens of callbacks I’d otherwise need to use.

As RxJava 2.0 draws ever-closer, I’ve been pretty keen to have a look at what I’ll be dealing with. It’s a pretty major update, so there’re a lot of changes and a lot of new things. Furthermore, interoperability between 1.x and 2.0 seems to be mostly in the hands of various third party maintainers.

There’s an excellent overview available on the RxJava wiki, but I thought it’d be worthwhile elucidating on the things about the upcoming release that I really like.

Backpressure

One of the principle differences between RxJava 1.x and 2.0 is how backpressure is handled. If you’re not aware, backpressure is an issue when you’re using what is known as a hot observable.

A hot observable is an observable which will immediately start emitting at its own pace with no regard for whatever might follow. Cold observables are the opposite — they’ll get pulled down at the rate whatever follows wants to pull ’em down at. This might seem like a trivial distinction, but it’s really not. Hot observables can be tricky.

The reason for this becomes apparent when you turn it up to eleven. A person tapping a button once per second is pretty manageable, right? How about two times per second? Ten? A thousand? What happens when the Observer immediately afterwards can’t keep up?

It doesn’t know what to do. It crashes. You probably get a big ol’ cryptic stacktrace in your inbox for some thread other than main. Bad times are had. 😭

Backpressure originally wasn’t considered when the first few iterations of the Observable class were written. According to the RxJava wiki, handling it was actually retroactively fitted. Obviously, from a design point, this was not at all ideal. RxJava 2.0 will thankfully remedy this with a new implementation of the Publisher interface and also with what’s known as a Flowable.

A Flowable, as opposed to the retrofitted 1.x Observable, immediately has the bits and bobs needed to adequately handle backpressure. If we actually look in the class, we’ll see —

/** The default buffer size. */
static final int BUFFER_SIZE;
static {
BUFFER_SIZE = Math.max(16, Integer.getInteger("rx2.buffer-size", 128));
}

— that it’s literally geared to be buffered from the get-go. That environment variable rx2.buffer-size, is a configurable value which we can set to anything we want, though the default is a reasonable 128. If we delve even deeper, we’ll see that this value is eventually used inside most of the operators such as flatMap, concat and so on to initialise a queue. So if we take flatMap as an example (from Flowable.java), we can see that it gets used here:

@BackpressureSupport(BackpressureKind.FULL)
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Flowable<R> flatMap(Function<? super T, ? extends Publisher<? extends R>> mapper) {
return flatMap(mapper, false, bufferSize(), bufferSize());
}

which then eventually leads to initialising the queue…

q = new SpscLinkedArrayQueue<U>(bufferSize);

…deep inside the guts of FlowableFlatMap.java. As you can see, it takes an integer as a parameter that sets the initial capacity.

Flowable.create() is also handled differently compared to 1.x’s Observable.create() and is actually closer to Observable.fromEmitter() in how it behaves. It takes a BackpressureMode, so you can specify exactly how you want backpressure to be handled, or if you don’t want it handled it all. I think that’s pretty nifty.

…throws Exception

This one’s pretty self-explanatory. I’m sure everyone’s had to do this sort of thing at least a few times:

String[] val = {"hi", "hello"};
Observable.just(val)
.map(v -> {
try {
someFunction(val);
} catch (CheckedException ex) {
throw new UncheckedException(ex);
}
}).etc();

Eugh. We all know that sucks. It’s messy and it’s unnecessary noise that you shouldn’t have to write, but you do. Maybe, if you’re really lazy, you’ll just catch Exception indiscriminately because…why not?

Now however, RxJava 2.x’s new functional interfaces will throw our checked exceptions for us. Straight through to wherever we’re handling our errors, so we don’t need to wrap all of our I/O in try-catch blocks just to keep things going. 🎉

Co-Existence With RxJava 1.x

One of the nice things about the packaging scheme for RxJava 2.0-RC2 is that it plays nice with RxJava 1.x. This is a bonus, because they’re both entirely different from one another. Hence, you can easily migrate from 1.x to 2.0 at your own pace. That’s way better than doing it all in one go, especially if what you’re working on is quite large.

This also lends itself to some cool stuff such as interoperability libraries, which let you map from an 1.x object to a 2.0 object. There are even a few floating around now, such as RxJava2Interop. That one in particular is maintained by a ReactiveX member, so it’s definitely something to keep an eye on.

I’d imagine that once RxJava 2.0 is released proper, interoperability libraries will become even more important, since the use of RxJava 1.x is quite prevalent. Android’s support of both versions will likely result in inventive wrappers to suit those who don’t necessarily want to reimplement the RxInnards of a larger library from the ground up.

What Else?

Just to round things off, here’s one last little thing that interests me. The new RxJavaPlugins and it’s applicability to testing. It’s going to be more flexible, allowing you to swap between what maps to where at runtime, so your tests can be a bit more flexible. All of the various hook classes now belong to RxJavaPlugins too, so you only have to worry about the one thing, rather than various different types of plugins and hooks just to get your tests set up the way you want.

About Us

At jtribe, we proudly craft software solutions for iOS, Android and Web and are passionate about our work. We’ve been working with the iOS and Android platforms since day one, and are one of the most experienced mobile development teams in Australia. We measure success on the impact we have, and with over six-million end users we know our work is meaningful, and this continues to be our driving force.

--

--