Working with RxJava Disposables in Kotlin

In this tutorial, you’ll learn the basics of RxJava Disposables. You will be building an app from scratch that retrieves real-time cryptocurrency data. By Lawrence Tan 🇸🇬.

Leave a rating/review
Download materials
Save for later
Share

In this tutorial, you’ll learn the basics of RxJava Disposables. You’ll build an app from scratch that retrieves real-time cryptocurrency data.

Note: This tutorial assumes you have some experience using RxJava. If you don’t, make a pit stop at this tutorial first before proceeding.

Note: This tutorial assumes you have some experience using RxJava. If you don’t, make a pit stop at this tutorial first before proceeding.

Reactive Android Programming consists of RxJava, RxAndroid and RxKotlin.
RxJava is the most touted Reactive Programming library in the Android Development world. It reduces many threading headaches and makes codes more intuitive.

RxAndroid is a lightweight module which binds Android specific components with RxJava classes.RxKotlin makes writing RxJava methods easier by providing convenient extension functions.

RxAssemble!

RxAssemble! You’ll use the basic functions of these three libraries to build the CryptoMe app in this tutorial.

Disposables

Disposables

What are Disposables? Disposable in plain English implies short-term convenience. This also means they are short lived or meant to be discarded after use. The same idea is conveyed in RxJava’s Disposables.

When an Observer subscribes to an Emitter, or Observables, you create a stream. This stream takes up resources which later become disposable “solid waste”. You need to handle this waste if the stream is going to run for a long time.

Observable has a method called onComplete() that will do the disposing for you when called. Many at times though, you will find it more beneficial and convenient to have the ability to cancel your subscriptions easily and at any time.

Today, you’ll tackle a more complex case. The stream will run endlessly and you’ll use Disposables to handle them to prevent memory leaks.

A Disposable is a stream or a link between an Observable and an Observer. A quick check of the documentation shows that it has two main methods, dispose() and isDisposed(). The former disposes of the link, while the latter checks if the link has been disposed.

Testing Disposables

When you establish a subscription between Observable and Observer, it returns a Disposable. For example, take a look at this code:

import android.util.Log
import io.reactivex.Observable
import java.util.concurrent.TimeUnit

object DisposableTester {

    @JvmStatic fun main() {
        val seconds = Observable.interval(1, TimeUnit.SECONDS)
        val disposable = seconds.subscribe({ l -> logData(l) })

        //sleep 10 seconds
        sleep(10000)

        //Dispose and stop emissions
        disposable.dispose()

        Log.d("Test","Disposed!")

        //Sleep 10 seconds to prove
        //There are no more emissions
        sleep(10000)
    }

    private fun logData(l: Long) {
        Log.d("Test","Received: " + l)
    }

    private fun sleep(millis:Int) {
        try {
            Thread.sleep(millis.toLong())
        }
        catch (e:InterruptedException) {
            e.printStackTrace()
        }
    }

}

An Observable runs and emits every second. After ten seconds of emissions, the Disposable resource returned from subscribe() is disposed of by explicitly calling dispose(). Then another ten seconds timer emits to verify that the resource is already disposed of.

Handling Disposables outside is one way to dispose of resources that are no longer needed. Since RxJava 2.0, the Observer has the ability to dispose of the subscription at any time. For an example:

import io.reactivex.Observer
import io.reactivex.disposables.Disposable

object DisposableTester {

    var myObserver: Observer<Int> = object: Observer<Int> {
        private var disposable: Disposable? = null

        override fun onSubscribe(disposable: Disposable) {
            this.disposable = disposable
        }
        override fun onNext(value:Int) {
            //Has access to Disposable
        }
        
        override fun onError(e:Throwable) {
            //Has access to Disposable
        }
        
        override fun onComplete() {
            //Has access to Disposable
        }
    }

}

If at any time the emissions are no longer required in onNext(), onError() or onComplete(), you can stop them.

CompositeDisposables

CompositeDisposable

As the app evolves, there are scenarios where you need more than one subscription. Retrieving live data from multiple sources in a travel app for hotel, tours and air tickets is one great example.

You need to use CompositeDisposables to manage the resources. It implements Disposable and then holds a collection of disposables. Here’s a quick example:

import android.util.Log
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import java.util.concurrent.TimeUnit

object DisposableTester {

    private val disposables = CompositeDisposable()

    @JvmStatic fun main() {
        val seconds = Observable.interval(1, TimeUnit.SECONDS)

        //Subscribe and capture disposables
        val disposable1 = seconds.subscribe({ l -> logData(l, 1) })
        val disposable2 = seconds.subscribe({ l -> logData(l, 2) })

        //Put both disposables into CompositeDisposable
        disposables.addAll(disposable1, disposable2)

        //Sleep 10 seconds
        sleep(10000)

        //Dispose all disposables
        disposables.dispose()

        Log.d("Test", ("All Disposed!"))

        //Sleep 10 seconds to prove
        //there are no more emissions
        sleep(10000)
    }

    private fun logData(l: Long, observerNumber: Int) {
        Log.d("Test", ("Observer " + observerNumber + ": " + l))
    }

    private fun sleep(millis:Int) {
        try {
            Thread.sleep(millis.toLong())
        } catch (e:InterruptedException) {
            e.printStackTrace()
        }
    }

}

In this implementation, the code leveraged on this simple utility which helps you manage a collection of Disposables. By calling add() or addAll(), you can dispose of them all at once when they’re no longer needed.

Congratulations! You’ve refreshed your knowledge on the basics of Reactive Programming and learned about Disposables. Now, you’re ready to embark on a journey in building the CryptoMe App!

CryptoMe App

Before you get started, take a look at what the app will look like once you’ve completed this tutorial.

The main page has two tabs. The Western Tab loads Crypto data from Western countries while the Eastern Tab loads Crypto data from Eastern countries.

The data comes from CryptoCompare API. You can sign up here for a free key with limited calls. The app polls for updated data every ten seconds.

By tapping on any Cryptocurrency, the app brings you to its web contents. You’ll learn to use Disposables to manage resources in this app.

Are you ready? Time to get started!

Getting Started

To get started, click on the Download Materials button at the top or bottom of this tutorial. First, explore the starter project in Android Studio 3.4.1 and above.

You’ll work on BaseFragment.kt where most of the network handling logic is. You’ll also implement some configurations in CryptoDataRepository.kt and CryptoDataViewModel.kt.

Take a look at some of the files. In App.kt, you’ll find Retrofit is the main network utility the app uses. In this file, you initialize Retrofit and use CryptoDataAPI to manage API calls.

CryptoDataRepository is a class which accepts an object and implements CryptoDataAPI. This class helps handle specific server data logic.

When the Observable receives data, it’ll process and integrate into CryptoDataViewModel. The ViewModel updates the RecyclerView which displays to users the latest crypto data.

The MainActivity contains a TabLayout, with each tab holding a single Fragment. HomeFragment and SecondFragment both inherit from BaseFragment, where most of the data processing work is.

FragmentAdapter helps populate the appropriate Fragment in each Tab. CryptoDataAdapter helps translate Data into RecyclerViews.

DetailActivity shows the web contents of a selected cryptocurrency.

Wow, that’s a lot to process!

Fear not! Having an organized project structure does reap benefits. You’ll see at the end how everything pieces together to build your very own CryptoMe app!

Now, build and run the project on your Android device or emulator. You should see a gorgeous empty search screen: