I am trying to migrate the following function to new Coroutine
of Kotlin 1.3
:
fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job {
return launch(context = UI, parent = strategy.jobs, block = block)
}
But new GlobalScope.launch
function doesn't have parent
parameter. Documentation says:
The parent job is inherited from a
CoroutineScope
as well, but it can also be overridden with correspondingcoroutineContext
element.
But I don't know how to override parent job. I have implemented it like this for now but I am not sure if it will work the same way:
fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job {
val job = GlobalScope.launch(context = Dispatchers.Main, block = block)
strategy.jobs.invokeOnCompletion {
job.cancel()
}
return job
}
Can anyone help me?
UPDATE:
class CancelStrategy(owner: LifecycleOwner, val jobs: Job) : LifecycleObserver {
init {
owner.lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
jobs.cancel()
}
}
Your second example is correct. You can use plus
to add the job as a parent job for the new coroutine.
fun launchUI(strategy: CancelStrategy, block: suspend CoroutineScope.() -> Unit): Job {
return GlobalScope.launch(context = Dispatchers.Main + strategy.jobs, block = block)
}
But the usage of GlobalScope
is discouraged. It would be better to create an own CoroutineScope
. Your CancelStrategy
looks like a good candidate.
class CancelStrategy(owner: LifecycleOwner, val jobs: Job) : LifecycleObserver, CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + jobs
init {
owner.lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
jobs.cancel()
}
}
Now you can start your coroutines like this:
cancelStrategy.launch { ... }
What you want to have is called "structured concurrency" by aligning the lifecycle of your coroutines to some UI component.
Have a look at this documentation: https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-concurrency-lifecycle-and-coroutine-parent-child-hierarchy
Instead of using GlobalScope
, you should consider implementing your own scope and maintaining a Job
their, which you can cancel to cancel all your children as well.
Here's a simplified example:
class Activity : CoroutineScope {
lateinit var job: Job //tied to lifecycle of Activity
fun create() {
job = Job()
}
fun destroy() {
//will cancel all child jobs as well
println("cancel $job and all ${job.children.toList().size} children")
job.cancel()
}
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + job + CoroutineName("MyActivityContext")
fun doSomething() {
//we launch in the outer scope of Activity
launch {
//...
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.