Search code examples
androidkotlinandroid-lifecycleandroid-livedatakotlin-coroutines

How to pass the result of a suspending function to a non-suspending function?


Let's say I have the function

suspend fun doSomething(): Result {
    val result = doStuff().await() //this is the suspending part
    return result
}

I now want to build a generic function which can take functions like the one above as a parameter. Its main goal is to turn the passed result into a livedata object:

fun getResultLiveData(resource: Result): LiveData<Result> = liveData(Dispatchers.IO) {
    emit(resource)
}

However, when I try calling the suspend function to get its result as a parameter, like so:

fun someLiveData = getResultLiveData(doSomething())

I get an (understandable) precompile exception for the part inside the brackets of getResultLiveData:

Suspend function doSomething() should be called only from a coroutine or another suspend function

This obviously makes sense, but how do i annotate the parameter for my getResultLiveData as the result of a suspending function?

Now, if i were to do something like:

fun getResultLiveData(): LiveData<Result> = liveData(Dispatchers.IO) {
    emit(doSomething())
}

It would work, because it is being called within the scope of a suspending part of the function (i.e. the LiveDataScope). But I just want to go one abstraction step further...


Solution

  • As suggested by @CommonsWare, the solution is to pass a suspending function itself, and not the result of the function as a parameter. This also works when the suspending function has parameters.

    The getResultLiveData function should look the following:

    fun getResultLiveData(resourceFunction: suspend () -> Result): LiveData<Result> = liveData(Dispatchers.IO) {
      emit(resourceFunction())
    }
    

    And then you could easily call the function within a lambda expression:

    getResultLiveData{doStuff(param1, param2)}
    

    or simply

    getResultLiveData{doStuff()}