How to Coroutine LiveData in ViewModel
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 :
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 :
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.
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 :
On the snippet above will give null result when we observe movieResult
. . 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.
When we observe the LiveData by observing discoverAllMovies()
in our Activity, it will give correct result.
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 :)