Xabier Gorostidi
10/01/2020, 10:00 AMclass Test(val callbackWork: CustomCallbackWork) : CoroutineScope {
private var job = Job()
override val coroutineContext: CoroutineContext
get() = <http://Dispatchers.IO|Dispatchers.IO> + job
fun start() : Flow<Unit> {
return channelFlow {
launch {
delay(5000)
logger().d("After delay, isActive: $isActive")
close()
}
launch {
callbackWork.apply {
onSuccess = {
offer(Unit)
coroutineContext.cancelChildren()
}
onError = {
offer(Unit)
coroutineContext.cancelChildren()
}
}
}
}
}
}
The log is printed (obviously displaying isActive=true
) after 5 seconds even though onSuccess
is triggered before that delay. However, if I get the reference of the first Job and cancel it below, it works perfectly. What's wrong in the code?Zach Klippenstein (he/him) [MOD]
10/01/2020, 1:50 PMcoroutineContext
is resolving to the extension on the scope instance that is the receiver of the launch lambda.
Store a reference to the scope of the callbackFlow before calling launch, to resolve to the right one and make it clear which scope you're referencing, then cancel that.Zach Klippenstein (he/him) [MOD]
10/01/2020, 1:54 PMXabier Gorostidi
10/01/2020, 2:04 PMval scope = this
in the first line of the start()
function and invoked scope.coroutineContext.cancelChildren()
within the callbacks. However the first coroutine isn't still cancelled and prints the log.Zach Klippenstein (he/him) [MOD]
10/01/2020, 2:20 PMcallbackFlow {
Xabier Gorostidi
10/01/2020, 2:51 PMchannelFlow { }
would run in a new producer scope which is different from the one of the Test
scope. In fact, if I move the scope to the first line and then use scope.launch { }
below, it also works because it's now referring to the same scope.Xabier Gorostidi
10/01/2020, 2:52 PMchannelFlow
will return the contest where it's being collected, which is pretty much reasonable, right?Zach Klippenstein (he/him) [MOD]
10/01/2020, 2:56 PMZach Klippenstein (he/him) [MOD]
10/01/2020, 3:00 PMval test = Test(…)
val flow = test.start()
flow.launchIn(scope)
flow.launchIn(scope)
delay(5000)
test.start().collect { }
Xabier Gorostidi
10/01/2020, 3:14 PM