An Introduction to RxJava for Android Developers

New Android Developers can easily become overwhelmed with RxJava and it’s complexity. In the series, let’s explore what problem RxJava solves and how you can start using it in your next Android app.

As an example, RxJava allows you to write 5-10 lines of code that can fetch information from a backend website, process the web request, and send the data as an Observable to all listeners. RxJava makes it easy to process data on a background thread and can even cache the data locally for use offline.

Android Developer use RxJava a lot for fetching information from the web on a background thread, but it has many use cases.

RxJava Use Cases

Podcast app
Imagine creating a podcast app that plays audio for the user. Each episode is probably is on a web server somewhere in the world, and each episode needs to be downloaded for the user to listen to it on her commute.

Newspaper app
Every day at 6am, download the day’s news using RxJava. Combined with WorkManager, app users will have fresh stories, ready to read.

Ecommerce app
Offer hundreds of products on an ecommerce app. All network requests can be cached on-device for offline browsing.

Dating app
Allow users to browse photos and messages. Use RxJava for all HTTP network calls.

In this series, we’ll use Android Studio and Kotlin, although you can substitute Kotlin for Java. Most advanced developers have already switched to 100% Kotlin, and it’s future looks bright. But code in Java if you are more comfortable.

RxJava Examples

What can be frustrating is that there are lots of things RxJava can do. How do we know what to use? And what do these illustrations mean? For example, the following is a diagram of zip:

How about an example? First, we need to add something to the Module’s Gradle file, io.reactivex.rxjava2:rxjava:2.2.2, as shown below.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:design:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    implementation "io.reactivex.rxjava2:rxjava:2.2.2"
}

We need to create our Episode model, which is a Kotlin data class. Create a new file called Episode.kt and paste in the following code.

data class Episode(
        val title: String,
        val episodeUrl: String
)

Good, now our data class is all set up. In this instance, we only need a title and episodeUrl.

Next, open MainActivity and add the following code into onCreate() but after setContentView(). This creates an Observable. Later, we will use this Observable to listen for updates, however long it takes to get the response from the server. It’s important to note that RxJava doesn’t care how long it takes to load data from the server.

        val observable = Observable.create(ObservableOnSubscribe<Episode> { emitter ->
            val episode = Episode("What a Wonderful World", "https://danielmalone.com/podcast/episode/25")
            emitter.onNext(episode)
        })

The important thing to note here is that we trigger onNext() passing in the episode. Also, the data we need it most likely in a List, probably using JSON.

Last, but not least, we need to add more code to onCreate, after the observable variable. Here we have four methods available to us: onSubscribe, onNext, onError and onComplete. Which method or methods get triggered? It depends. As we subscribe, onSubscribe() is called. Then onNext() will receive the episodes from the above code (episode 25). Or if there is an error, onError() will be triggered, giving us a Throwable.

        observable.subscribe(object : Observer<Episode> {
            override fun onComplete() {
            }

            override fun onSubscribe(d: Disposable) {
            }

            override fun onNext(t: Episode) {
                d("daniel", "episode? ${t.title}")
            }

            override fun onError(e: Throwable) {
            }
        })

Run the code, open Logcat, and see if you can find the message “daniel.”. You should see something like the following.

09-22 13:28:06.028 23494-23494/com.example D/daniel: episode? What a Wonderful World

In this case, we need only an onSuccess() or onError(). With this in mind, let’s transform the above code into the following.

        val observable = Single.create(SingleOnSubscribe<Episode> { emitter ->
            val episode = Episode("What a Wonderful World", "https://danielmalone.com/podcast/episode/25")
            emitter.onSuccess(episode)
        })

        observable.subscribe(object : DisposableSingleObserver<Episode>() {
            override fun onSuccess(t: Episode) {
            }

            override fun onError(e: Throwable) {
            }
        })

We’re still returning one Episode, but in real life, you may want to return a list of episodes with List<Episode>, as opposed to just one Episode.

With the exception of the logic inside of our Single.create() call, this is basic usage of RxJava. In real life, we would replace Single.create() and put our logic to fetch a list of episodes from a web API (like Firebase, Google Cloud Platform, AWS, etc.).

What if we want to perform the Single.create() on a background thread? This is an important usability issue because we don’t want the UI thread stop updating and responding to the user. Let’s perform this on a background thread.

Add the following to the build.gradle file:

    implementation "io.reactivex.rxjava2:rxjava:2.2.2"
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'

Now let’s update our MainActivity.kt file:

        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : DisposableSingleObserver<Episode>() {
                    override fun onSuccess(t: Episode) {
                    }

                    override fun onError(e: Throwable) {
                    }
                })

Now the Single.create() method’s work is performed on a background thread, not the UI thread. This call will feel smooth to the user. In real life, if the HTTP network request takes 10 seconds, the user will still be able to interact with and use the Android app.

About the author

Daniel Malone
Bringing more than a decade of software engineering experience, Daniel Malone is Editor at androidEveryday. An Austin native, Daniel is often found reading technical books, blogging and creating YouTube tutorials. When not working, he likes to listen to pop hits on Google Play Music.

findViewById() in Kotlin

  • As you may have discovered, findViewByid() is no longer needed.
  • Kotlin adds the ability to directly access Views.

1 week ago

Android Architecture Components Tutorial: ViewModel + LiveData

  • Use Kotlin to build a basic Android app using Android Architecture Components.
  • As part of Jetpack, LiveData and ViewModel support a MVVM app architecture.

3 weeks ago

Android SharedPreferences Tutorial in Kotlin

  • Use SharedPreferences to store simple data in Android Studio projects.
  • It's good for storing small amounts of data

    3 weeks ago