How to Coroutine LiveData in ViewModel

heri sulistiyanto
Ruangguru Engineering
3 min readNov 8, 2019
Photo by Rami Al-zayat on Unsplash

As we know lately . . Kotlin Coroutine become hot topic in Android development. Usually i’m using RxJava in my Android project, and i decide to take a look on Coroutine for a simple project and share my “experience” in this story.

I’m using Retrofit (2.6.1) in my demo project, which already support for suspend function. Let’s take a look in my MovieApiService below :

retrofit interface which using suspend function

From the snippet above, we see that all of the function return object Retrofit Response not Deferred.

And then, i have a BaseDataSource which is the base abstract class for the DataSource, and here’s the snippet code :

BaseDataSource

This BaseDataSource, we wrap the Retrofit Response into 2 type in the getResult function, ResponseResult.Success and ResponseResult.Error.

In resultLiveData function, we gonna wrap the suspend function result as LiveData by emitting the object.

MovieRemoteDataSource extends BaseDataSource

Take a look on snippet above. Both of function will return LiveData using the function from the BaseDataSource. So when those function invoked, it should give LiveData immediately right? ummmm . . . not quite right though.

So here’s my experience i mentioned earlier.

Usually, when we work using ViewModel & LiveData, we put like . . . let say 2 variable which will store value to be observe :

My first approach, but fail :(

On the snippet above will give null result when we observe movieResult . . but why?

But why??

So it seem our DataSource won’t emitting data because the LiveData (from our remote data source) mark as no active observer. And then i change the approach, for the function in our viewmodel become not return Unit but return LiveData instead.

My 2nd approach, and it works :)

When we observe the LiveData by observing discoverAllMovies() in our Activity, it will give correct result.

Observing LiveData in Activity

Please take a look at :

dashboardViewModel.discoverAllMovies().onResult {
vfDashboardContent.displayedChild = when(it) {
is ResponseResult.Success -> {
val data = it.result.data?.mapToMovieItemList()
movieAdapter.setListMovieData(data)
DashboardStateView.STATE_CONTENT
}
is ResponseResult.Loading -> {
DashboardStateView.STATE_LOADING
}
is ResponseResult.Error -> {
tvCommonError.text = it.msg.errorMsg.orEmpty()
DashboardStateView.STATE_ERROR
}
}
}

On above block, the live data can be observed (not null) and result will be handled by the state, then update current UI.

After this demo project, i realise that the livedata{} on coroutine need to be observe directly, so it can emitting data.

You can find the full source code in my github.

If you find this article helpful, please give your warmest clap :)

Photo by Pete Pedroza on Unsplash

--

--