Colton Idle
10/26/2023, 1:58 PMfun getThing(): Thing {
val innerThing = runBlocking { otherThing.getThing() }
return Thing(innerThing.foo)
}
I can instead pass a scope into getThing(), but it didn't work as I expected. i.e.
fun getThing(scope: CoroutineScope): Thing {
val innerThing = scope.launch { otherThing.getThing() }
return Thing(innerThing.foo)
}
doesnt compile ^myanmarking
10/26/2023, 1:59 PMCasey Brooks
10/26/2023, 2:06 PMscope.launch
returns a Job
, while runBlocking
returns the value of the lambda. They are not interchangeable. scope.async { }
is closer to what you want, but you’ll need to call .await()
to get the value, which is also a suspending function.
In general, it’s going to be difficult to mix suspending and non-suspending code in any logically-useful way. The best you can do is set up callbacks for everything just like you would have to do in Java, and then coroutines then become not much different than working with standard Threads.
It’s best to make everything suspending, and then only at the last possible moment tie everything in to the non-suspending world. For example, do this instead:
suspend fun getThing(): Thing {
val innerThing = otherThing.getThing()
return Thing(innerThing.foo)
}
and then push back the responsibility for creating and managing the coroutine to somewhere else (i.e. the Android ViewModel`
class MyViewModel : ViewModel() {
val thingStateFlow = MutableStateFlow<Thing?>(null)
fun loadAThing() {
viewModelScope.launch {
thingStateFlow.value = getThing()
}
}
}
Mikhail
10/26/2023, 2:13 PMCoroutineScope
it means you are already in some coroutine. So, in my opinion, the best solution is mark getThing
as suspend
Colton Idle
10/26/2023, 2:15 PMMikhail
10/26/2023, 2:25 PMval innerThingFuture = scope.async { otherThing.getThing() }.asCompletableFuture()
And deal with future in non-coroutine code.