Chapters

Hide chapters

Reactive Programming with Kotlin

Second Edition · Android 10 · Kotlin 1.3 · Android Studio 4.0

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

Section II: Operators & Best Practices

Section 2: 7 chapters
Show chapters Hide chapters

1. Hello, RxJava!
Written by Alex Sullivan & Marin Todorov

This book aims to introduce you, the reader, to the RxJava, RxKotlin and RxAndroid libraries and to writing reactive Android apps with Kotlin.

Defining RxJava and RxKotlin

You may be asking yourself “Wait, why am I reading about RxJava when I’m using Kotlin to build Android apps?” Great question! RxJava has been around since 2013, well before developers began to accept Kotlin as a mainstream programming language, and is part of a long list of Rx-based libraries written for different platforms and systems. Since Kotlin has such excellent interoperability with Java, it wouldn’t make sense to completely rewrite RxJava for Kotlin — you can just use the existing RxJava library instead!

However, just because RxJava doesn’t need to be completely rewritten to work in Kotlin doesn’t mean that it couldn’t benefit from all of the great features in the Kotlin programming language.

That’s where RxKotlin comes into play. RxKotlin is a library that expands RxJava by adding a ton of utilities and extension methods that make working with RxJava much more pleasant in Kotlin. That being said, since RxJava is a complete library on its own you absolutely do not need RxKotlin to use the RxJava library in a Kotlin-based Android app.

But what exactly is RxJava? Here’s a good definition:

RxJava is a library for composing asynchronous and event-based code by using observable sequences and functional style operators, allowing for parameterized execution via schedulers.

Sound complicated? Don’t worry if it does. Writing reactive programs, understanding the many concepts behind them and navigating a lot of the relevant, commonly used lingo might be intimidating — especially if you try to take it all in at once, or when no one has introduced it to you in a structured way.

That’s the goal of this book: to gradually introduce you to the various RxJava APIs and Rx concepts by explaining how to use each of the APIs, and then covering their practical usage in Android apps.

You’ll start with the basic features of RxJava, and then gradually work through intermediate and advanced topics. Taking the time to exercise new concepts extensively as you progress will make it easier to master RxJava by the end of the book. Rx is too broad of a topic to cover completely in a single book; instead, we aim to give you a solid understanding of the library so that you can continue developing Rx skills on your own.

We still haven’t quite established what RxJava is though, have we? Start with a simple, understandable definition and progress to a better, more expressive one as we waltz through the topic of reactive programming later in this chapter.

RxJava, in its essence, simplifies developing asynchronous programs by allowing your code to react to new data and process it in a sequential, isolated manner. In other words, RxJava lets you observe sequences of asynchronous events in an app and respond to each event accordingly. Examples are taps by a user on the screen and listening for the results of asynchronous network calls.

As an Android app developer, this should be much more clear and tell you more about what RxJava is, compared to the first definition you read earlier in this chapter.

Even if you’re still fuzzy on the details, it should be clear that RxJava helps you write asynchronous code. And you know that developing good, deterministic, asynchronous code is hard, so any help is quite welcome!

Introducing asynchronous programming

If you tried to explain asynchronous programming in a simple, down-to-earth language, you might come up with something along the lines of the following:

An Android app, at any moment, might be doing any of the following things and more:

  • Reacting to button taps
  • Animating a view across the screen
  • Downloading a large photo from the internet
  • Saving bits of data to disk
  • Playing audio

All of these things seemingly happen at the same time. Whenever the keyboard animates out of the screen, the audio in your app doesn’t pause until the animation has finished, right?

All the different bits of your program don’t block each other’s execution. Android offers you several different APIs that allow you to perform different pieces of work on different threads and perform them across the different cores of the device’s CPU.

Writing code that truly runs in parallel, however, is rather complex, especially when different bits of code need to work with the same pieces of data. It’s hard to determine which piece of code updates the data first or which code has read the latest value.

Using Android asynchronous APIs

Google has provided several different APIs that help you write asynchronous code. You’ve probably used a few of them before, and chances are they left you feeling a bit frustrated or maybe even scared.

You’ve probably used at least one of the following:

  • AsyncTask: To do some work on the background and then update elements in your UI with the result of that background work. You have to make sure to properly handle canceling a running AsyncTask when your Activity or Fragment shuts down since you could otherwise get a NullPointerException when the AsyncTask tries to update UI elements that don’t exist anymore.

  • IntentService: To start a fire-and-forget background job using an Intent. You typically use an IntentService if you want to do some work that doesn’t need to touch the UI at all — saving an object to a database, for example.

  • Thread: To start background work in a purely Java way without interacting with any Android APIs. Threads come with the downside of being expensive and not bound to any sort of ThreadPool.

  • Future: To clearly chain work which will complete at some undetermined point in the future. Futures are considerably clearer to use than AsyncTasks, but run into some of the same problems around null pointers when a Fragment or Activity has been destroyed.

The above isn’t an exhaustive list — there’s also Handler, JobScheduler, WorkManager, HandlerThread and Kotlin coroutines.

Comparing Coroutines and RxJava

Now that Kotlin coroutines have started to become popular in the Android development world, you may be asking yourself if it’s still worthwhile to learn about RxJava.

Many comparisons have been made between using RxJava and using coroutines for Android development. Each review will give you a different answer about which tool you should use.

In reality, RxJava and coroutines work at different levels of abstractions. Coroutines offer a more lightweight approach to threading and allow you to write asynchronous code in a synchronous manner. Rx, on the other hand, is used primarily to create the event-driven architecture mentioned above, and to allow you to write reactive applications. So, while they both offer an answer for doing asynchronous work off the main thread, they’re really different tools that are both useful depending on the context.

If you’re simply looking for an easy way to replace AsyncTask, then coroutines may make more sense than pulling RxJava into your application. However, if you do want to move towards a reactive, event-driven architecture, then RxJava is your best bet!

Understanding asynchronous programming challenges

Since most of your typical classes would do something asynchronously, and all UI components are inherently asynchronous, it’s impossible to make assumptions about what order the entirety of your app code will get executed.

After all, your app’s code runs differently depending on various external factors, such as user input, network activity, or other OS events. Each time the user fires up your app, the code may run in a completely different order depending on those external factors. (Well, except for the case when you have an army of robots testing your app, then you can expect all events to happen with precise, kill-bot synchronization.)

We’re definitely not saying that writing good asynchronous code is impossible. After all, there’s a litany of tools — like the ones listed above — that Android developers have been using to write asynchronous apps since well before RxJava hit the scene.

The issue is that complex asynchronous code becomes very difficult to write in part because of the variety of APIs that you as an Android developer will end up using:

You may be using an AsyncTask to update your UI, an IntentService to save something to a database, a WorkManager task to sync your app to a server, and other various asynchronous APIs. Since there is no universal language across all the asynchronous APIs, reading and understanding the code, and reasoning about its execution, becomes difficult.

To wrap up this section and put the discussion into a bit more context, you’ll compare two pieces of code: one synchronous and one asynchronous.

Synchronous code

Performing an operation for each element of a list is something you’ve done plenty of times. It’s a very simple yet solid building block of app logic because it guarantees two things: It executes synchronously, and the collection is immutable from the outside world while you iterate over it.

Take a moment to think about what this implies. When you iterate over a collection, you don’t need to check that all elements are still there, and you don’t need to rewind back in case another thread inserts an element at the start of the collection. You assume you always iterate over the collection in its entirety at the beginning of the loop.

If you want to play a bit more with these aspects of the for loop, try this in an app or IntelliJ IDEA project:

var list = listOf(1, 2, 3)
for (number in list) {
  println(number)
  list = listOf(4, 5, 6)
}
print(list)

Is list mutable inside the for body? Does the collection that the loop iterates over ever change? What’s the sequence of execution of all commands? Can you modify number if you need to? You may be surprised by what you see if you run this code:

1
2
3
[4, 5, 6]

Asynchronous code

Consider similar code, but assume each iteration happens as a reaction to a click on a button. As the user repeatedly clicks on the button, the app prints out the next element in a list:

var list = listOf(1, 2, 3)
var currentIndex = 0
button.setOnClickListener {
  println(list[currentIndex])

  if (currentIndex != list.lastIndex) {
    currentIndex++
  }
}

Think about this code in the same context as you did for the previous one. As the user clicks the button, will that print all of the list’s elements? You really can’t say. Another piece of asynchronous code might remove the last element, before it’s been printed.

Or another piece of code might insert a new element at the start of the collection after you’ve moved on.

Also, you assume only that the click listener will ever change currentIndex, but another piece of code might modify currentIndex as well — perhaps some clever code you added at some point after crafting the above function.

You’ve likely realized that some of the core issues with writing asynchronous code are: a) the order in which pieces of work are performed and b) shared mutable data.

These are some of RxJava’s strong suits!

Next, you need a good primer on the language that will help you start understanding how RxJava works, what problems it solves, and ultimately let you move past this gentle introduction and into writing your first Rx code in the next chapter.

Constructing an asynchronous programming glossary

Some of the language in RxJava is so tightly bound to asynchronous, reactive and/or functional programming that it will be easier if you first understand the following foundational terms.

In general, RxJava tries to address the following aspects of app development:

1. State, and specifically, shared mutable state

State is somewhat difficult to define. To understand state, consider the following practical example.

When you start your laptop it runs just fine, but after you use it for a few days or even weeks, it might start behaving weirdly or abruptly hang and refuse to speak to you. The hardware and software remains the same, but what’s changed is the state. As soon as you restart, the same combination of hardware and software will work just fine once more.

The data in memory, the data stored on disk, all the artifacts of reacting to user input, all traces that remain after fetching data from cloud services — the sum of these and more is the state of your laptop.

Managing the state of your Android apps, especially when shared between multiple asynchronous components, is one of the issues you’ll learn how to handle in this book.

2. Imperative programming

Imperative programming is a programming paradigm that uses statements to change the program’s state. Much like you would use imperative language while playing with your dog — “Fetch! Lay down! Play dead!” — you use imperative code to tell the app exactly when and how to do things.

Imperative code is similar to the code that your computer understands. All the CPU does is follow lengthy sequences of simple instructions. The issue is that it gets challenging for humans to write imperative code for complex, asynchronous apps — especially when shared, mutable state is involved.

For example, take this code, found in onCreate() of an Android Activity:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  setupUI()
  bindClickListeners()
  createAdapter()
  listenForChanges()
}

There’s no telling what these methods do. Do they update properties of the Activity itself? More disturbingly, are they called in the right order? Maybe somebody inadvertently swapped the order of these method calls and committed the change to source control. Now the app might behave differently due to the swapped calls.

3. Side effects

Now that you know more about mutable state and imperative programming, you can pin down most issues with those two things to side effects.

Side effects are any change to the state outside of the current scope. For example, consider the piece of code in the example above. bindClickListeners() probably attaches some kind of event handlers to some widgets. This causes a side effect, as it changes the state of the view: the app behaves one way before executing bindClickListeners(), and differently after that.

Side effects are also defined at the level of individual functions in your code. If a function modifies any state other than the local variables defined inside the function, then the function has introduced a side effect.

Any time you modify data stored on disk or update the text of a TextView on screen, you cause side effects.

Side effects are not bad in themselves. After all, causing side effects is the ultimate goal of any program! You need to change the state of the world somehow after your program has finished executing.

Running for a while and doing nothing makes for a pretty useless app.

The issue with producing side effects is doing it in a controlled way. You need to be able to determine which pieces of code cause side effects, and which simply process and output data.

RxJava tries to address the issues (or problems) listed above by utilizing the remaining two concepts.

4. Declarative code

In imperative programming, you change state at will. An alternative style of programming to imperative is functional programming. In functional code, you don’t cause any side effects.

Since we don’t live in a perfect world, the balance lies somewhere in the middle of these two extremes. RxJava combines some of the best aspects of imperative code and functional code.

In addition to not causing side effects, functional code tends to be declarative. Code is declarative when it focuses on the what that you want to do, instead of the how that encompasses the imperative way of programming. Declarative code lets you define pieces of behavior, and RxJava will run these behaviors any time there’s a relevant event and then provide the behaviors an immutable, isolated data input to work with.

By programming declaratively, you can work with asynchronous code, but make the same assumptions as in a simple for loop: that you’re working with immutable data and you can execute code in a sequential, deterministic way.

5. Reactive systems

“Reactive systems” is a rather abstract term and covers web or mobile apps that exhibit most or all of the following qualities:

  • Responsive: Always keep the UI up to date, representing the latest app state.
  • Resilient: Each behavior is defined in isolation and provides for flexible error recovery.
  • Elastic: The code handles varied workload, often implementing features such as lazy pull-driven data collections, event throttling, and resource sharing.
  • Message driven: Components use message-based communication for improved reusability and isolation, decoupling the lifecycle and implementation of classes.

In short, reactive systems react to user and other events in a flexible and coherent fashion.

The terms and concepts defined above are just the start of your RxJava vocabulary. You’ll see more terms as you progress through the book. Now that you have a start on understanding the problems RxJava helps solve and how it approaches these issues, it’s time to talk about the building blocks of Rx and how they play together.

Learning the foundations of RxJava

Reactive programming isn’t a new concept; it’s been around for a fairly long time, but its core concepts have made a noticeable comeback over the last decade.

In that period, web applications have became more involved and are facing the issue of managing complex asynchronous UIs. On the server side, reactive systems (as described above) have become a necessity.

A team at Microsoft took on the challenge of solving the problems of asynchronous, scalable, real-time application development that we’ve discussed in this chapter. They worked on a library, independently from the core teams in the company, and sometime around 2009, offered a new client and server-side framework called Reactive Extensions for .NET (Rx).

It was an installable add-on for .NET 3.5 and later became a built-in core library in .NET 4.0. It’s been an open-source component since 2012. Open sourcing the code permitted other languages and platforms to reimplement the same functionality, which turned Rx into a cross-platform standard.

Today you have RxJS, RxSwift, Rx.NET, RxScala, RxJava, and more. All these libraries strive to implement the same behavior and same expressive APIs. Ultimately, a developer creating an Android app with RxJava can freely discuss app logic with another programmer using RxJS on the web or RxSwift on iOS.

Like the original Rx, RxJava works with all the concepts you’ve covered so far: It tackles mutable state, it allows you to compose event sequences and improves on architectural concepts such as code isolation, reusability and decouplings.

Let’s revisit that definition:

RxJava finds the sweet spot between traditionally imperative Java/Kotlin code and purist functional code. It allows you to react to events by using immutable code definitions to asynchronously process pieces of input in a deterministic, composable way.

You can read more about the family of Rx implementations at http://reactivex.io. This is the central repository of documentation about Rx’s operators and core classes. It’s also probably the first place you’ll notice the Rx logo, the electric eel:

Note: I personally thought for some time that it was a piece of seaweed, but research shows that it is, in fact, an electric eel. (The Rx project used to be called Volta.)

In this book, you are going to cover both the cornerstone concepts of developing with RxJava as well as real-world examples of how to use them in your apps.

The three building blocks of Rx code are observables, operators and schedulers. The sections below cover each of these in detail.

Observables

The Observable<T> class provides the foundation of Rx code: the ability to asynchronously produce a sequence of events that can “carry” an immutable snapshot of data T. In the simplest words, it allows classes to subscribe for values emitted by another class over time.

The Observable<T> class allows one or more observers to react to any events in real time and update the app UI, or otherwise process and utilize new and incoming data.

The ObservableSource<T> interface (which the Observable<T> class implements) is extremely simple. An Observable can emit (and observers can receive) only three types of events:

  • A next event: An event which “carries” the latest (or next) data value. This is the way observers “receive” values.
  • A complete event: This event terminates the event sequence with success. It means the Observable completed its life-cycle successfully and won’t emit any other events.
  • An error event: The Observable terminates with an error and will not emit other events.

When talking about asynchronous events emitted over time, you can visualize an observable sequence of integers on a timeline, like so:

The blue boxes are the next events being emitted by the Observable. The vertical bar on the right represents the complete event. An error event would be represented by an x on the timeline.

This simple contract of three possible events an Observable can emit is anything and everything in Rx. Because it is so universal, you can use it to create even the most complex app logic.

Because the observable contract does not make any assumptions about the nature of the Observable or the Observer, using event sequences is the ultimate decoupling practice.

You don’t ever need to use callbacks to allow your classes to talk to each other.

To get an idea about some real-life situations, you’ll look at two different kinds of observable sequences: finite and infinite.

Finite observable sequences

Some observable sequences emit zero, one or more values, and, at a later point, either terminate successfully or terminate with an error.

In an Android app, consider code that downloads a file from the internet:

  • First, you start the download and start observing for incoming data.
  • Then you repeatedly receive chunks of data as parts of the file come in.
  • In the event the network connection goes down, the download will stop and the connection will time-out with an error.
  • Alternatively, if the code downloads all the file’s data, it will complete with success.

This workflow accurately describes the lifecycle of a typical observable. Take a look at the related code below:

API.download(file = "http://www...")
  .subscribeBy(
    onNext = {
      // append data to a file
    },
    onComplete = {
      // use downloaded file
    },
    onError = {
      // display error to user
    }
  )

API.download() returns an Observable<String> instance, which emits String values as chunks of data come over the network. Calling subscribeBy tells the observable that you’d like to subscribe for events that you’re going to provide lambdas for.

You subscribe to next events by providing the onNext lambda. In the downloading example, you append the data to a temporary file stored on disk.

You subscribe to an error event by providing the onError lambda. In the lambda, you can display a Throwable.message in an alert box or do something else.

Finally, to handle a complete event, you provide the onComplete lambda, where you can do something like start a new Activity to display the downloaded file or anything else your app logic dictates.

Infinite observable sequences

Unlike file downloads or similar activities, which are supposed to terminate either naturally or forcefully, there are other sequences which are simply infinite. Often, UI events are such infinite observable sequences.

For example, consider the code you need to react to a Switch being toggled in your app:

  • You add an OnCheckedChangedListener to the switch you want to listen to.
  • You then need to provide a lambda callback to the OnCheckedChangeListener. It looks at the isChecked value and updates the app state accordingly.

This sequence of switch checked changes does not have a natural end. As long as there is a switch on the screen, there is a possible sequence of switch checked changes. Further, since the sequence is virtually infinite, you always have an initial value at the time you start observing it — namely, whether the switch is on or off.

It may happen that the user never toggles the switch, but that doesn’t mean the sequence of events is terminated. It just means that there were no events emitted.

In RxJava, you could write code like this to react to the switch changing:

switch.checkedChanges()
  .subscribeBy(
    onNext = { isOn ->
      if (isOn) {
        // toggle a setting on
      } else {
        // toggle a setting off
      }
    }
  )

checkedChanges() is a soon-to-be-discovered extension method on CompoundButton that produces an Observable<Boolean>. (This is very easy to code yourself; you’ll learn how in upcoming chapters).

You subscribe to the Observable returned from checkedChanges() and update the app settings according to the current state of the switch. Note that you skip the onError and onComplete parameters to subscribeBy, since these events will not be emitted from that observable — a switch is either on or it’s not.

Operators

ObservableSource<T> and the implementation of the Observable class include plenty of methods that abstract discrete pieces of asynchronous work, which can be composed together to implement more complex logic.

Because they are highly decoupled and composable, these methods are most often referred to as operators. Since these operators mostly take in asynchronous input and only produce output without causing side effects, they can easily fit together, much like puzzle pieces, and work to build a bigger picture.

For example, take the mathematical expression (5 + 6) * 10 - 2.

In a clear, deterministic way, you can apply the operators *, ( ), + and - in their predefined order to the pieces of data that are their input, take their output and keep processing the expression until it’s resolved.

In a somewhat similar manner, you can apply Rx operators to the pieces of input emitted by an Observable to deterministically process inputs and outputs until the expression has been resolved to a final value, which you can then use to cause side effects.

Here’s the previous example about observing switch changes, adjusted to use some common Rx operators:

switch.checkedChanges()
  .filter { it == true }
  .map { "We've been toggled on!" }
  .subscribeBy(
    onNext = { message ->
      updateTextView(message)
    }
  )

Each time checkedChanges() produces either a true or false value, Rx will apply the filter and map operators to that emitted piece of data.

First, filter will only let through values that are true. If the switch has been toggled off the subscription code will not be executed because filter will restrict those values.

In case of true values, the map operator will take the Boolean type input and convert it to a String output — the text "We've been toggled on!".

Finally, with subscribeBy you subscribe for the resulting next event, this time carrying a String value, and you call a method to update some text view with that text onscreen.

The operators are also highly composable — they always take in data as input and output their result, so you can easily chain them in many different ways, achieving much more than what a single operator can do on its own!

As you work through the book, you will learn about more complex operators that abstract even more-involved pieces of asynchronous work.

Schedulers

Schedulers are similar to the ThreadPools that you see in normal Java and Kotlin code. If you’re not familiar with ThreadPools, you can think of them as a collection of Threads that are all joined together and available to use.

RxJava comes with a number of predefined schedulers, which cover 99% of use cases. Hopefully, this means you will never have to go about creating your own scheduler.

In fact, most of the examples in the first half of this book are quite simple and generally deal with observing data and updating the UI, so you won’t look into schedulers at all until you’ve covered the basics.

That being said, schedulers are very powerful.

For example, you can specify that you’d like to observe for next events on the IO scheduler, which makes your Rx code run on a background thread pool — you may want to use this scheduler if you’re downloading files from the network or saving something to a database.

TrampolineScheduler will run your code concurrently. The ComputationScheduler will allow you to schedule your subscriptions on a separate set of Threads that are reserved for heavy lifting computation tasks.

Thanks to RxJava, you can schedule the different pieces of work of the same subscription on different schedulers to achieve the best performance. Even if they sound very interesting and quite handy, don’t bother too much with schedulers for now. You’ll return to them later in the book.

App architecture

It’s worth mentioning that RxJava doesn’t alter your app’s architecture in any way; it mostly deals with events, asynchronous data sequences and a universal communication contract.

You can create apps with Rx by implementing a normal Model-View-Controller (MVC) architecture. You can also choose to implement a Model-View-Presenter (MVP) architecture or Model-View-ViewModel (MVVM) if that’s what you prefer.

In case you’d like to go that way, RxJava is also very useful for implementing your own unidirectional data-flow architecture.

It’s important to note that you definitely do not have to start a project from scratch to make it a reactive app; you can iteratively refactor pieces of an exiting project or simply use RxJava when appending new features to your app.

The MVVM architecture was originally developed by Microsoft specifically for event-driven software created on platforms which offers data bindings. RxJava and MVVM definitely do play nicely together, and towards the end of this book you’ll look into that pattern and how to implement it with RxJava.

The reason MVVM and RxJava go great together is that a ViewModel allows you to expose Observable<T> properties, which you can bind directly to UI widgets in your Activity, or translate them into LiveData objects from Android Jetpack and then subscribe to those instead. This makes binding model data to the UI very simple to represent, and to code. You’ll see how to integrate the use of RxJava with LiveData later in the book.

RxAndroid and RxBinding

RxJava is the implementation of the common Rx API. Therefore, it doesn’t know anything about any Android-specific classes.

There are two companion libraries that can be used to fill in a few of the gaps between Android and RxJava.

The first is a tiny library called RxAndroid. RxAndroid has one specific purpose: to provide a bridge between Android’s Looper class and RxJava’s schedulers. Chances are, you’ll use this library simply to receive the results of an Observable on the UI thread so that you can update your views.

The second library is a broader library called RxBinding. RxBinding provides a large number of utility methods to turn callback-styled view listeners into observables. You actually already saw an example of this library being used, the checkedChanges() method used earlier on a Switch:

switch.checkedChanges()
  .subscribeBy(
    onNext = { boolean ->
      println("Switch is on: $boolean")
    }
  )

checkedChanges() is an extension method provided by the RxBinding library to turn a normal CompoundButton like Switch into a stream of on or off states.

RxBinding provides similar bindings for many of the Android view classes, such as listening for clicks on a Button and changes to the text in an EditText.

Installing RxJava

RxJava is available for free at https://github.com/ReactiveX/RxJava.

RxJava is distributed under the Apache-2.0 license, which, in short, allows you to include the library in free or commercial software, on an as-is basis. As with all other Apache-2.0 licensed software, the copyright notice should be included in all apps you distribute.

Including RxJava in a Gradle-based project, such as an Android app, takes two lines — add the following to the dependencies block in your module’s build.gradle file:

implementation "io.reactivex.rxjava3:rxjava:3.0.2"
implementation "io.reactivex.rxjava3:rxkotlin:3.0.0"

The first implementation line is for RxJava. The second is for including the RxKotlin extensions. You can omit the RxJava import if you include RxKotlin, but since the RxKotlin library may not include the latest RxJava library, it’s good practice to include both. You’ll generally want to include the latest versions of both libraries.

Note: You may have noticed that the dependency for RxJava actually says rxjava3 in it. There’s three major versions of RxJava: RxJava1, RxJava2, and RxJava3. RxJava2 added a lot of useful new tricks and types to the library, while RxJava3 added Java8 support. This book will be using RxJava3. You can find some of the differences between the versions in the What’s different in 2.0 article: https://github.com/ReactiveX/RxJava/wiki/What’s-different-in-2.0, and the What’s different in 3.0 article: https://github.com/ReactiveX/RxJava/wiki/What’s-different-in-3.0)

Community

The RxJava project is alive and buzzing with activity, not only because Rx is inspiring programmers to create cool software with it, but also due to the positive nature of the community that formed around this project.

The RxJava community is very friendly, open minded, and enthusiastic about discussing patterns, common techniques, or just helping each other.

You can find channels dedicated to talking about RxJava in both the Android United Slack and the official Kotlin Slack.

The first can be found, here: http://android-united.community/. If you request an invite, it should be approved quickly.

The official Kotlin Slack can be found here: https://kotlinlang.slack.com/.

Search for rx in both Slacks and you should find what you’re looking for!

Both Slacks are friendly and inviting. The members are always available to troubleshoot some particularly tricky Rx code, or to discuss the latest and greatest in the world of RxJava and RxKotlin.

Key points

  • RxJava is a library that provides an Rx framework for Java-based projects such as Android apps.
  • RxJava can be used even when using the Kotlin language for app development.
  • The RxKotlin library adds some Kotlin related utilities and extensions on top of RxJava.
  • RxJava and all Rx frameworks provide for a way to program using asynchronous, event-based code.
  • RxJava helps you build reactive systems in a declarative style.
  • The main elements you’ll use in RxJava are observables, operators, and schedulers.
  • The RxAndroid and RxBinding libraries assist you in using RxJava on Android.

Where to go from here?

This chapter introduced you to many of the problems that RxJava addresses. You learned about the complexities of asynchronous programming, sharing mutable state, causing side effects and more.

You haven’t written any RxJava yet, but you now understand why RxJava is a good idea and you’re aware of the types of problems it solves. This should give you a good start as you work through the rest of the book.

And there is plenty to work through! You’ll start by creating very simple observables and work your way up to complete real-world Android apps using the MVVM architecture.

Move right on to Chapter 2, “Observables”!

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.