我正在探索在Android UI线程上下文中使用协同例程。我contextJob
按照《协程指南》 UI中所述进行了实施。后台工作是从GUI开始的,我想在每次单击时重新启动它(停止当前正在运行的操作,然后重新启动)。
但是一旦取消的工作就无法重复使用,因此即使创建子工作:
val job = Job(contextJob)
取消它并没有帮助,因为必须重新分配它。
有没有办法重用Job实例?
一个工作有设计一个非常简单的生命周期。它的“已完成”状态是最终状态,与Android的“已销毁”状态非常相似Activity
。因此,如指南中所述,Job
最好将父项与关联Activity
。当且仅当活动被销毁时,才应取消上级工作。由于无法重用已销毁的活动,因此您永远不会遇到重用其工作的需求。
推荐使用actor来启动每次单击的工作,因为它们可以帮助您避免不必要的并发。该指南显示了如何在每次单击时启动它们,但未显示如何取消当前运行的操作。
您需要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
在每次点击时开始播放。但是,每次对an的调用action
都包装在自己的Job
usingwithContext
块中,因此可以从其父作业中分别取消它。
请注意,此代码可以正常执行不可取消的操作或需要花费一些时间才能取消的操作。一个动作在取消时可能需要清理其资源,并且由于此代码使用了一个actor,因此它可以确保在开始下一个动作之前完成对上一个动作的清理。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句