我有以下设置:
override suspend fun doWork(): Result = coroutineScope {
flowOfEvents
.onEach(eventChannel::send)
.launchIn(this)
if (isQueueEmpty()) return@coroutineScope Result.success()
...
}
我看到的是:当isQueueEmpty()
为真时,我返回Result.success()
,我希望flowOfEvents...launchIn(this)
流也会被处理/取消,但我一直从该流接收事件。
我做错什么了吗?
从launchIn(this)
捕获Job并在每个返回语句之前显式调用job.cancel()
可以工作,但感觉没有必要/错误。
经过一番研究,发现这是Kotlin协同程序的行为,与WorkManager
完全无关。
- 听
Flow<Event>
是一项永无止境的工作 - 根据定义,父协同程序等待子协同程序完成
考虑到这两点,现在很明显,为什么我从父协同程序返回后仍会收到Event
s。
解决方案:在从父协同程序返回之前调用coroutineContext[Job]?.cancelChildren()
。
override suspend fun doWork(): Result = coroutineScope {
flowOfEvents
.onEach(eventChannel::send)
.launchIn(this)
if (isQueueEmpty()) {
coroutineContext[Job]?.cancelChildren()
return@coroutineScope Result.success()
}
...
}
注意:调用父级的cancel()
会抛出一个CancellationException
,在WorkManager
的上下文中,这意味着Worker#doWork
方法实际上会导致作业失败