RxBinding provides RxJava
binding APIs for Android User Interface (UI) widgets. This allows us to easily translate Android UI events into Observable
streams. Let’s look at a simple example of this: we’re going to consider how to execute an asynchronous network request from a Button
click event.
build.gradle File
The first thing we need to do is update our application’s build.gradle file. We’re going to add the dependencies needed for RxJava2, RxAndroid, and RxBinding:
dependencies {
// RxJava
compile 'io.reactivex.rxjava2:rxjava:latest_version'
compile 'io.reactivex.rxjava2:rxandroid:latest_version'
compile 'com.jakewharton.rxbinding2:rxbinding-kotlin:latest_version'
}
Depending on the support libraries that you are using in your application, you will need to include one or more of the following dependencies:
compile '...:rxbinding-support-v4-kotlin:latest_version'
compile '...:rxbinding-appcompat-v7-kotlin:latest_version'
compile '...:rxbinding-recyclerview-v7-kotlin:latest_version'
The full listing is available here.
Sample Application
Our sample application will consist of one Activity, named RxBindingActivity
. This contains a Button
which when clicked will load a list of users from a remote API into a TextView
and then display a Toast
.
For our networking layer we’re going to use Retrofit. This will allow us to define our desired /users
endpoint with the following:
@GET("/users")
fun getUsers(): Single<List<User>>
Notice how we simply specify our method and its return value. In this a case a Single
of type List<User>
. We decided to use a Single
here as it works best when you don’t expect to receive multiple values. Then in our RxBindingActivity
class we can retrieve and log the list of users with the following code:
fun getAllUsers(): Single<List<User>> {
return api.getUsers()
.subscribeOn(Schedulers.io())
.onErrorResumeNext(Single.just(emptyList()))
.doOnSuccess { Timber.i("users: $it") }
}
We’re also using the onErrorResumeNext
operator to emit an empty List
in the case where we receive an error from the API.
Handling Click Events
Now that we can retrieve the list of users, we want to connect this to our Button
. For that we will use the clicks()
Extension method which is available on View
elements from the rxbinding-kotlin
dependency. First, we get access to our desired view element by means of the lazy
delegate available in Kotlin. Then we apply the clicks()
method on the Button
.
val myButton: Button by lazy { findViewById(R.id.button) as Button }
...
myButton.clicks()
If we take a look at the Extension method from RxView.kt
we can see that it returns an Observable<Unit>
. This means that we can then apply any desired RxJava
operators as we see fit. It’s also important to note that the created Observable
has a strong reference to the View
so we need to make sure we clean up after ourselves when we’re done.
Connecting the newly created Observable
to our API request can be done by using the flatMapSingle
operator. This will allow us to transform our Observable<Unit>
to Single<List<User>>
.
So we’ll use the following code to do just that:
myButton.clicks()
.observeOn(Schedulers.io())
.flatMapSingle { getAllUsers() }
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
this::handleUsers,
this::handleError
)
Next, to tie it all together we subscribe()
to the Single
and provide method references to deal with both the success and error cases. That’s all we need to handle as we’re working with a Single
. However, we’re not done yet. Recall we mentioned that we need to clean up after ourselves when dealing with the Observable
created from the clicks()
method. For that we have a few different options. The simplest way to handle it is to store the reference as a Disposable
and then call its dispose
method when we’re done with the Activity.
var disposable: Disposable? = null
override fun onResume() {
...
disposable = myButton.clicks()
.observeOn(Schedulers.io())
.flatMapSingle { getAllUsers() }
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
this::handleUsers,
this::handleError
)
}
override fun onPause() { disposable?.dispose() super.onPause() }
The complete source code for the sample application can be found here. I’d love to see more examples of RxBinding being used with Kotlin. If you know of any, please leave a reference in the comments section. Thanks!
Special thanks to: @PatrickDattilio, @donnfelker, @kaushikgopal and @moyheen for reviewing this post!