Android 取消自定义协同作用域

Android 取消自定义协同作用域,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,如果我将scope.cancel()放在启动外部,它会立即取消协同路由,而不调用启动块代码。这是预期的吗?为什么会发生?如果我希望协同路由在启动内部完成代码后结束,是否应将取消放在启动块末尾的启动内部 更新 根据Hau Luu的回答和Marko Topolnik的评论 “在发布结束时,我认为任务已经完成,您不需要这样做 手动取消协同程序。“ 及 任务完成后,协同程序将从内存中消失 但在案例2中,如果我启动另一次启动,它将被执行,除非我们像案例1那样取消第一次启动中的协同程序。 那么,是否有任何保

如果我将
scope.cancel()
放在启动外部,它会立即取消协同路由,而不调用启动块代码。这是预期的吗?为什么会发生?如果我希望协同路由在启动内部完成代码后结束,是否应将取消放在启动块末尾的启动内部

更新

根据Hau Luu的回答和Marko Topolnik的评论

“在发布结束时,我认为任务已经完成,您不需要这样做 手动取消协同程序。“


任务完成后,协同程序将从内存中消失

但在案例2中,如果我启动另一次启动,它将被执行,除非我们像案例1那样取消第一次启动中的协同程序。 那么,是否有任何保证,在任务完成后,协同路由会从内存中消失,而不需要我们手动调用cancel()?Bcoz编译器永远不会知道最后一次启动是在哪个启动之后执行,之后需要结束协同路由

案例1

val scope = CoroutineScope(
        Job() + Dispatchers.Main
)
scope.launch {
    beforeExecute()
    val result = withContext(dispatcher) { doInBackground(*params) }
    if (!isCancelled) {
        postExecute(result)
    } else {
        cancelled(result)
    }
    status = Status.FINISHED
}
scope.cancel()
仅打印任务1

案例2

scope.launch {
    Log.e("Task","1");
    scope.cancel()
}
scope.launch {
    Log.e("Task","2");
}

任务1和任务2都被打印出来

您的代码可以翻译成自然语言,即“在scope.launch执行之后立即取消给定的协同程序”,因此我认为这是预期的行为

对于另一个问题,我们只想在执行过程中出现错误时取消一个协程-嘿,协程,在我给你的任务执行过程中。如果发生了什么错误。自杀。因此,在发布结束时,我认为任务已经完成,您不需要手动取消协同程序

更新:我写这个作为一个答案,因为我不能在注释中写代码

CoroutineScope的设计目的是对创建/启动/容纳一个coroutine的对象的生命周期作出反应。因此,当您在一个CoroutineScope上调用cancel方法时,您停止了所有操作。停止而不是取消。由作用域创建的所有子协同路由,它们正在执行的所有作业,全部取消,仅此而已。工作完成了。这就是为什么在scope.cancel之后无法启动另一次启动

CoroutineScope将通过launch和async等构建器方法创建并保存对一组Corruuntine的引用。当您要取消特定的协同程序时。您需要取消生成器返回的作业。不要取消容纳他们的范围


任务2将正常打印。

除非正在执行此协程的对象已被处理,且其结果不再相关,否则不应取消作用域。如果在发布启动块后立即取消作用域,您期望会发生什么?@Pawel我希望一旦我的任务完成,那么协同程序应该停止运行。协同程序的AIK生命周期取决于我们使用的作用域,就像如果我使用viewmodelscope之类的内置示波器,那么lifecyale将与viewmodel的生命周期相关联。但我在这里我正在使用自定义协同路由作用域。如何确保任务完成后协同路由不会保留在内存中?我在抽象类final方法中使用此代码,任务在
status=status.FINISHED
行后完成。正如您所说,viewmodelscope绑定到viewmodel的生命周期,所以您应该将您的范围绑定到类的生命周期。为一个协同程序执行声明范围毫无意义。若它是静态方法,那个么你们最好把它发布在
GlobalScope
上,因为协同程序一旦完成执行,就不会在内存中逗留。@Pawel我相信GlobalScope和应用程序的生命周期有关,不应该被使用@是的!理论上,应该是这样。但由于我无法检查CS(协同路由镜)的存在,所以我无法确认它。因为作用域内的协同路由的生命周期可能比启动它的方法的生命周期长。协同路由的AIK生命周期取决于我们使用的作用域,例如,如果我使用的是viewmodelscope之类的内置Inscope,则生命周期与viewmodel的生命周期相关联。但在这里,我使用的是自定义协同路由。我如何确保协同路由不受影响一旦我的任务完成,还记得吗?我相信我需要使用cancel!一旦任务完成,协同程序就会从内存中消失。在这方面,它与
线程
非常相似。您不会执行
thread.start();thread.interrupt(),协同程序也是如此。@MarkoTopolnik编译器能知道在结束协同程序之后,最后一次执行的启动是哪一次吗?请根据您的评论和Hau Luu的回答检查我问题中的“更新”部分。您可能认为
scope
是协同程序吗
CoroutineScope
只是一个简单的数据对象,它不包含任何资源
launch
创建一个协同程序,完成后,它将消失。仅当由于应用程序中某个组件的生命周期即将结束而要突然取消仍在范围内运行的所有协同程序时,才使用
scope.cancel()
。我已更新了答案,因为注释编辑器很难使用。很抱歉
scope.launch {
    Log.e("Task","1");
}
scope.launch {
    Log.e("Task","2");
}
val job1 = scope.launch{ print('Task 1') }
job1.cancel()
val job2 = scope.launch{ print('Task 2') }