paint-brush
Managing Network State using RxJavaby@elye.project
1,382 reads
1,382 reads

Managing Network State using RxJava

by ElyeJuly 12th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

We often use RxJava for fetching network result, but usually have it tell us either Success or Error. How nice if it could also tell us Loading and perhaps Empty (nothing loaded) state as well, so we don’t need to handle that logic separately, and have it communicate to the View the State result.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Managing Network State using RxJava
Elye HackerNoon profile picture

We often use RxJava for fetching network result, but usually have it tell us either Success or Error. How nice if it could also tell us Loading and perhaps Empty (nothing loaded) state as well, so we don’t need to handle that logic separately, and have it communicate to the View the State result.

Get started

I believe the RxJava code below is no longer stranger to anyone who has coded a network call.

service.fetchResult()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
                { data -> process(data) },
                { error -> report_error(error) }
        )

It’s supercool, as it helps one to put the network request to the background easily, and handle the result or result easily.

Get greedier

A lot of times, we want something more than just Data or Error. While waiting for the fetching, we want to show Loading State on the UI. If the result comes back as empty result, we want to show Empty State.

In order to achieve that, we write more code surrounding the above Rx fetching code (within our presenter perhaps) to handle and update the UI accordingly.

How nice if we could do that all in RxJava, as per illustrate in the diagram below.

Get smarter

Thinking about it, we could possibly do that. Instead of handling all the logic in our presenter, we have use a model that represent all the state.

Here I defined it as below

data class UiStateModel (
        private val inProgress: Boolean = false,
        private val errorMessage: String? = null,
        private val dataModel: DataModel? = null
) {

    fun isLoading() = inProgress
    fun isError() = errorMessage != null
    fun isSuccess() = 
         dataModel?.dataString?.isNotEmpty() ?: false && !isError()
    fun isEmpty() = 
         !inProgress && errorMessage == null && !isSuccess()

}

We could setup the Model that store inProgress flag, errorMessage and data. Based on these info, the model could be used to check if it is in Loading, Error, Success or Empty state.

To make this better, we could make the having some static class that instantiate UiStateModel per the state.

companion object {
    fun loading() = UiStateModel(inProgress = true)
    fun success(dataModel: DataModel) 
        = UiStateModel(dataModel = dataModel)
    fun error(error: Throwable) 
        = UiStateModel(errorMessage = error.message)
}

Get linked

So with this model now we have could represent the state, how we could combined to make use of it? Check out the code below that is used in the presenter.

service.fetchResult()
        .map { data -> UiStateModel.success(data) }
        .onErrorReturn 
             { exception -> UiStateModel.error(exception) }
        .startWith(UiStateModel.loading())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({
            uiState ->
            when {
                uiState.isLoading() -> view.isLoading()
                uiState.isError() -> 
                       view.isError(uiState.getErrorMessage())
                uiState.isSuccess() -> 
                       view.isSuccess(uiState.getData())
                uiState.isEmpty() -> view.isEmpty()
                else -> IllegalArgumentException("Invalid Response")
            }
        })

After fetching the result from the server, if it is successful, we convert it into a success UiStateModel. If it is error, we use onErrorReturn to convert it into an error UiStateModel.

The nice bit here is, on start, we could use startWith to convert it to loading UiStateModel.

We now have all the states specified, including empty State, which is handled internally within the UiStateModel to define it’s state.

Get code

I’ve made code example showing the flow in https://github.com/elye/demo_rxjava_manage_state

It shows all the states scenarios as below. Have fun!

The example here is a very simplified example as per shared by Jake Wharton. Check it out further for more insights.

Presentation: The State of Managing State with RxJava

Click “❤” below to share. Thanks! ~Twitter:elye; Facebook:elye