Android: Reactive View Part I
- Android: Reactive View Part I ← This Post Is Here!
- Android: Reactive View Part II
- Android: Reactive View Part III
Originally published at bloggie.io.
A few years back, to make a network call or running a long running process in Android development, we need to use AsyncTask
, but it has its own drawbacks.
Then, RxJava came along and gained a lot of popularity in Android development to solve this issue.
So when I learned about RxJava, I thought that the library is only used for making background job and switching threads more convenient.
But I was so wrong about it!
The main purpose of RxJava is for making event processing easier.
In this post I want to talk about how to use RxJava to make the View
layer reactive in Android development, instead of just using RxJava just to make network calls like I used to do.
Pre-requisite
This post is targeted for readers who have some experience with RxJava, ViewModel, MVP, MVVM, LiveData, Kotlin, because I will be using a little bit of everything in this post.
Imaginary Spec
Let’s pretend we want to create a home page. Where we want to make a page like this:
Description
- has one
button
- when the
button
is clicked, it makes a network call to get morePosts
- the result of network call will populate the
RecyclerView
1. Starting with Simple Network Calls
Let’s begin by looking at how to make a simple network call with RxJava, it would look like this:
// MainActivitky.ktfun onCreate() {
setContentView(...)
someApi.getMorePosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newPosts ->
recyclerView.submitList(newPosts)
}
}
Pretend api.getPosts()
is a network call that returns an Observable
:
// SomeApi.ktinterface SomeApi {
fun getMorePosts(): Observable<List<Post>>
}
This is pretty straight forward if you know a little of RxJava.
2. Button click
Next, we make the network call to be triggered by a button click. The MainActivity.kt
would look like this:
// MainActivitky.ktfun onCreate() {
setContentView(...)
button.setOnClickListener {
someApi.getMorePosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newPosts ->
recyclerView.submitList(newPosts)
}
}
}
This is a working implementation, however the view layer is not made reactive yet.
3. MVP Architecture + Non-Reactive View Layer
Before going into making View Layer reactive, let’s add a simple MVP implementation, since it’s a very common pattern.
In the MVP Architecture, it would look something like this:
// MainActivitky.ktclass MainActivity: AppCompatActivity(), SomePresenter.View {
val somePresenter = SomePresenter(this)
fun onCreate() {
setContentView(...)
button.setOnClickListener {
somePresenter.onButtonClick()
}
}
override fun updateRecyclerView(newPosts: List<Post>) {
recyclerView.submitList(newPosts)
}
}// MainPresenter.ktclass SomePresenter(val view: SomePresenter.View) {
fun onButtonClick() {
someApi.getMorePosts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newPosts ->
view.updateRecyclerView(newPosts)
}
}
interface View {
fun updateRecyclerView(newPosts: List<Post>)
}
}
As you can see in the example, whenever the button
is clicked, somePresenter.onButtonClick()
has to be called manually.
4. MVP Architecture + Reactive View Layer
Next, let’s try to make the View Layer reactive. Here’s how the button
can be made reactive. 👇
By using the RxBinding library by Jake Wharton, the button
(or any View
type can be made reactive through extension function using clicks()
.
// MainActivitky.ktclass MainActivity: AppCompatActivity(), SomePresenter.View {
val buttonObservable by lazy { button.clicks() }
val somePresenter by lazy {
SomePresenter(this, buttonObservable)
} fun onCreate() {
setContentView(...)
somePresenter.onCreate()
}
override fun updateRecyclerView(newPosts: List<Post>) {
recyclerView.submitList(newPosts)
}
}
Note that after the button
is made to be reactive, the buttonObservable
is passed into the Presenter
through the constructor.
// MainPresenter.ktclass SomePresenter(
val view: SomePresenter.View,
val buttonObservable: Observable<Unit>) {
fun onCreate() {
buttonObservable.flatMap { someApi.getMorePosts() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newPosts ->
view.updateRecyclerView(newPosts)
}
}
interface View {
fun updateRecyclerView(newPosts: List<Post>)
}
}
Inside the Presenter
, the buttonObservable
can be subscribed
to and used as a trigger to the network call someApi.getMorePosts()
.
5. Discussion
In this trivial example, both methods (non-reactive view vs. reactive view) don’t look too different. At this point, the difference is very trival so choosing whichever method seems to be completely up to one’s preference. There is however still something interesting to look at.
In the non-reactive flow, the Activity
which is also the View
will have to make the call to presenter.onButtonClick()
.
Let’s take a look at the Reactive Flow.
In the reactive flow, the button click is turned into an Observable
, and pass into Presenter
's constructor. It is up to the Presenter
to decide how to subscribe
to this Observable
.
The main purpose of this post is to make a simple comparison between the 2, but without a more complex example, it’s hard to see how each one perform.
To keep this post short, I wrote Android: Reactive View Part II.
Originally published at bloggie.io.