有没有办法重用作业实例?



我正在探索在Android UI线程上下文中使用协程。我按照协程指南 UI 中所述实现了contextJob。后台工作从 GUI 开始,我想在每次单击时重新启动它(停止当前正在运行的工作并重新启动它)。

但是,一旦取消的作业就不能重复使用,因此即使创建子作业:

val job = Job(contextJob)

取消它无济于事,因为它必须重新分配。

有没有办法重用作业实例?

作业在设计上具有非常简单的生命周期。它的"已完成"状态是最终状态,与AndroidActivity的"已销毁"状态非常相似。因此,父Job最好与Activity相关联,如指南中所述。当且仅当活动被销毁时,才应取消父作业。由于已销毁的活动无法重用,因此您永远不会遇到重用其作业的需要。

在每次单击时开始工作的建议方法是使用执行组件,因为它们可以帮助您避免不必要的并发。该指南显示了如何在每次单击时启动它们,但没有显示如何取消当前正在运行的操作。

您将需要一个新的Job实例与withContext结合使用,以使代码块可以与其他所有内容分开:

fun View.onClick(action: suspend () -> Unit) {
var currentJob: Job? = null // to keep a reference to the currently running job
// launch one actor as a parent of the context job
// actor prevent concurrent execution of multiple actions
val eventActor = actor<Unit>(contextJob + UI, capacity = Channel.CONFLATED) {
for (event in channel) {
currentJob = Job(contextJob) // create a new job for this action
try {
// run an action within its own job
withContext(currentJob!!) { action() }
} catch (e: CancellationException) {
// we expect it to be cancelled and just need to continue
}
}
}
// install a listener to send message to this actor
setOnClickListener {
currentJob?.cancel() // cancel whatever job we were doing now (if any)
eventActor.offer(Unit) // signal to start next action when possible
}
}

参与者始终处于活动状态,直到其父作业(附加到活动)被取消。参与者等待点击并在每次点击时开始action。但是,action的每次调用都使用withContext块包装到其自己的Job中,以便可以将其与其父作业分开取消。

请注意,此代码适用于不可取消或只需一些时间才能取消的操作。操作在取消时可能需要清理其资源,并且由于此代码使用执行组件,因此可确保在启动下一个操作之前完成对上一个操作的清理。

相关内容

  • 没有找到相关文章

最新更新