Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to pass LiveData in ViewModel taken from suspended Repository

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?

like image 908
DominikS Avatar asked Feb 22 '20 10:02

DominikS


People also ask

Can we use LiveData in repository?

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.

Why use flow instead of LiveData?

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.

Should I return repository LiveData?

Repositories should be kept free of framework dependencies, and with that also LiveData since it is tied to the lifecycle.

What is mutable live data?

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.


1 Answers

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

like image 65
Alex Krafts Avatar answered Oct 11 '22 14:10

Alex Krafts