Android: Reactive View Part I

Tan Jun Rong avatar
Tan Jun Rong

This post is the 1st part of the series of blog posts I'm writing about making Android view layer Reactive.

  1. Android Reactive View Part I ← This Post Is Here!
  2. Android Reactive View Part II
  3. Android: Reactive View Part III.
 Photo by Andrew Santellan on Unsplash
Photo by Andrew Santellan on Unsplash

RxJava is not only for threading

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 it's 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

  1. has one button
  2. when the button is clicked, it makes a network call to get more Posts
  3. 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.kt
fun onCreate() { setContentView(...) someApi.getMorePosts() // 1. make network call .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { newPosts -> recyclerView.submitList(newPosts) // 2. show result on screen } }

Pretend api.getPosts() is a network call that returns an Observable:

SomeApi.kt
interface 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.kt
fun 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.kt
class 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.kt
class 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.kt
class 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.kt
class 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.

Non-Reactive Flow
Non-Reactive Flow

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.

Reactive Flow
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.