Search code examples
kotlinandroid-livedatakotlin-coroutinesandroid-viewmodel

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?


Solution

  • 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