Issue
I have a function that should do its work but also trigger a background process. The triggered process, even though launched within the function, should not hold it from returning because it is not directly related to the work being done.
Code example:
suspend fun coroutiny(): String {
coroutineScope {
launch(Dispatchers.IO) {
delay(1000)
println("Independent thing that should not avoid coroutiny to return")
}
}
return "Coroutiny return"
}
suspend fun main() {
println(coroutiny())
println("after coroutiny")
delay(2000)
}
My Desired result in this situation would be:
Coroutiny return
after coroutiny
Independent thing that should not avoid coroutiny to return
But what I get is:
Independent thing that should not avoid coroutiny to return
Coroutiny return
after coroutiny
I know this happens because coroutineScope {...} only returns when the coroutines inside return/complete. What I need help with is to know how to do what I want without resorting to GlobalScope.launch {...}, which I wanted to avoid as my use case does not match the documented acceptable use cases for GlobalScope.
Solution
As you noted, the approach with coroutineScope
is meant to parallelize work inside your suspend function, but all the work should be finished once you return.
If you want to launch coroutines that live longer than your function's scope, you would need to use some CoroutineScope
in which you can launch that coroutine.
The usual approach to get a scope is to make your function an extension on CoroutineScope
. It then becomes the responsibility of the caller to provide a coroutine scope to your function (just like launch
and async
are designed). Also, usually these functions are non-suspending (because suspend functions are expected to finish all the work before returning).
fun CoroutineScope.coroutiny(): String {
launch(Dispatchers.IO) {
delay(1000)
println("Independent thing that should not avoid coroutiny to return")
}
return "Coroutiny return"
}
fun main() = runBlocking {
println(coroutiny())
println("after coroutiny")
delay(2000)
}
Output (try it yourself):
Coroutiny return
after coroutiny
Independent thing that should not avoid coroutiny to return
If your function lives inside a component that has a lifecycle, and if it makes sense to tie the life of the launched coroutines to that lifecycle, then another option is to create a CoroutineScope
as a property of that component, and cancel it appropriately at the end of the component's lifecycle.
class MyClassWithLifecycle {
private val scope = CoroutineScope(CoroutineName("my-custom-processing"))
fun coroutiny(): String {
scope.launch(Dispatchers.IO) {
delay(1000)
println("Independent thing that should not avoid coroutiny to return")
}
return "Coroutiny return"
}
fun someCloseOrDisposeFunction() {
scope.cancel()
}
}
If you're on Android, Kotlin extension libraries provide those scopes out of the box, such as lifecycleScope
or viewModelScope
in the most important components with lifecycles.
Answered By - Joffrey
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.