I'm wrapping my head around Kotlin coroutines and LiveData. I want to do really basic use case where ViewModel returns LiveData taken from Repository suspended function, which returns LiveData as well.
Repository function signature:
suspend fun getAll() : LiveData<List<Mountain>>
It can't simply do that:
fun getMountains() : LiveData<List<Mountain>> {
return mountainsRepository.getAll()
}
because the compiler states that suspend function should be called from coroutine or another suspend function. I came up with 2 ugly solutions, but I know they aren't elegant:
1 Solution with runBlocking
fun getMountains() : LiveData<List<Mountain>> = runBlocking { mountainsRepository.getAll() }
2 Solution with nullable LiveData
fun getMountains() : LiveData<List<Mountain>>?{
var mountains : LiveData<List<Mountain>>? = null
viewModelScope.launch{
mountains = mountainsRepository.getAll()
}
return mountains
}
How can I do this properly?
LiveData objects should not live in the repository. // noticeable jank in the UI! If you need to use streams of data in other layers of your app, consider using Kotlin Flows and then converting them to LiveData in the ViewModel using asLiveData() . Learn more about using Kotlin Flow with LiveData in this codelab.
StateFlow and LiveData have similarities. Both are observable data holder classes, and both follow a similar pattern when used in your app architecture. The StateFlow and LiveData do behave differently: StateFlow requires an initial state to be passed into the constructor, while LiveData does not.
Repositories should be kept free of framework dependencies, and with that also LiveData since it is tied to the lifecycle.
MutableLiveData is just a class that extends the LiveData type class. MutableLiveData is commonly used since it provides the postValue() , setValue() methods publicly, something that LiveData class doesn't provide.
There is a liveData builder that can call suspend functions in its body. So your view model function can look like
fun getMountains() = liveData {
emit(mountainsRepository.getAll())
}
make sure you are using at least
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
And as Lena mentioned - removing suspend
from your repository getAll()
function do not make it blocking.
Having
fun getAll() : LiveData<List<Mountain>>
in your repo, and
fun getMountains() = mountainsRepository.getAll()
in your view model, could be a better way to achieve the same goal
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With