quver
03/19/2019, 8:34 PMJob
was added to the coroutineContext
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
?streetsofboston
03/19/2019, 8:40 PMJob
and cancel it when necessaryquver
03/19/2019, 8:44 PMlaunch
or async
it will attach to the scope
so then I will write
override fun onDestroy() {
super.onDestroy()
coroutineContext.cancelChildren()
}
streetsofboston
03/19/2019, 8:45 PMjob
will be a SupervisorJob
. In the ViewModels’ onClear, you’d call the cancel
method on that private val job = SupervisorJob()
abstract class CoBaseViewModel(context: CoroutineContext) : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext = SupervisorJob() + context
override fun onCleared() {
coroutineContext.cancel()
}
}
context
is usually just the Dispatchers.Main
)quver
03/19/2019, 8:54 PM+job
we can specify in which Job
will be linked launch
or async
?streetsofboston
03/19/2019, 8:56 PMjob
from that point onquver
03/19/2019, 9:00 PMJob()
by default, right?streetsofboston
03/19/2019, 9:04 PMquver
03/19/2019, 9:05 PMprivate val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
streetsofboston
03/19/2019, 9:10 PMjob
. It’s a pattern 🙂quver
03/19/2019, 9:23 PMSupervisorJob
to avoid stop parent coroutines by children crash.
but why we need a job above. we stop all jobs by coroutineContext.cancelChildren()
and if we want pause some specific job we save it instance from launch
and then stop it.
but what is best practise for this parent job?streetsofboston
03/19/2019, 9:29 PMcancelChildren
suffices. But if your coroutine-scope and its context participates in structured concurrency, the calling context may need all its children to finish before it continues of finishes. That would mean cancelChildren
is not enough, you’d need to call cancel
to cancel your top-job.quver
03/19/2019, 9:32 PMstreetsofboston
03/19/2019, 9:33 PMquver
03/19/2019, 9:36 PM+job
there isn't default job. and by coroutineContext.cancelChildren()
there isn't crash because of ?.
but also there isn't cancelation.gildor
03/20/2019, 12:53 AMget() = Dispatchers.Main + jobInstead of this idiom you also can consider ready to user
MainScope()
class CoBaseViewModel : ViewModel(), CoroutineScope by MainScope()
it uses SupervisorJob by default and Main thread dispatcher
One more thing: keeping reference on job or use coroutineContext
to cancel job is not necessary, there is CoroutineScope.cancel()
extension function, so for ViewModel you can just do this:
override fun onCleared() {
super.onCleared()
cancel()
}
we stop all jobs byWhat is your use case for this? Fragments? Because for ViewModel it looks wrong, less error-prone to cancel Job, so if you have some async bug and will try to start coroutine after cancellation, this coroutine will be cancelled immediately, but withcoroutineContext.cancelChildren()
coroutineContext()
you will get leaked coroutine insteadstreetsofboston
03/20/2019, 1:20 AMgildor
03/20/2019, 1:25 AMclass CoBaseViewModel(context: CoroutineContext) : ViewModel(), CoroutineScope by MainScope() + context
class CoBaseViewModel(scope: CoroutineScope) : ViewModel(), CoroutineScope by scope
quver
03/20/2019, 9:03 AMgildor
03/20/2019, 9:03 AMquver
03/20/2019, 9:04 AMgildor
03/20/2019, 9:04 AMquver
03/20/2019, 9:07 AMMainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)
and in my example was
private val job = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
gildor
03/20/2019, 9:14 AMstreetsofboston
03/20/2019, 9:51 AMgildor
03/20/2019, 9:54 AM