其他
协程中的取消和异常 | 核心概念介绍
CoroutineScope
CoroutineScope https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/ launch https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html async https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
viewModelScope https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#(androidx.lifecycle.ViewModel).viewModelScope:kotlinx.coroutines.CoroutineScope lifecycleScope https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#lifecyclescope
//Job 和 Dispatcher 已经被集成到了 CoroutineContext
//后面我们详细介绍
val scope = CoroutineScope(Job() + Dispatchers.Main)
val job = scope.launch {
//新的协程
}
Job
Job 用于处理协程。对于每一个您所创建的协程 (通过 launch 或者 async),它会返回一个 Job 实例,该实例是协程的唯一标识,并且负责管理协程的生命周期。正如我们上面看到的,您可以将 Job 实例传递给 CoroutineScope 来控制其生命周期。
Job https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
CoroutineContext
Job: 控制协程的生命周期; CoroutineDispatcher: 向合适的线程分发任务; CoroutineName: 协程的名称,调试的时候很有用; CoroutineExceptionHandler: 处理未被捕捉的异常,在未来的第三篇文章里会有详细的讲解。
CoroutineContext https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/index.html
val scope = CoroutineScope(Job() + Dispatchers.Main)
val job = scope.launch {
// 新的协程会将 CoroutineScope 作为父级
val result = async {
// 通过 launch 创建的新协程会将当前协程作为父级
}.await()
}
△ 协程是以任务层级为序执行的。
Job 的生命周期
一个任务可以包含一系列状态: 新创建 (New)、活跃 (Active)、完成中 (Completing)、已完成 (Completed)、取消中 (Cancelling) 和已取消 (Cancelled)。虽然我们无法直接访问这些状态,但是我们可以访问 Job 的属性: isActive、isCancelled 和 isCompleted。
如果协程处于活跃状态,协程运行出错或者调用 job.cancel() 都会将当前任务置为取消中 (Cancelling) 状态 (isActive = false, isCancelled = true)。当所有的子协程都完成后,协程会进入已取消 (Cancelled) 状态,此时 isCompleted = true。
解析父级 CoroutineContext
在任务层级中,每个协程都会有一个父级对象,要么是 CoroutineScope 或者另外一个 coroutine。然而,实际上协程的父级 CoroutineContext 和父级协程的 CoroutineContext 是不一样的,因为有如下的公式:
一些元素包含默认值: Dispatchers.Default 是默认的 CoroutineDispatcher,以及 "coroutine" 作为默认的 CoroutineName; 继承的 CoroutineContext 是 CoroutineScope 或者其父协程的 CoroutineContext; 传入协程 builder 的参数的优先级高于继承的上下文参数,因此会覆盖对应的参数值。
Dispatchers.IO
http://dispatchers.io/
val job = scope.launch(Dispatchers.IO) {
//新协程
}
△ CoroutineContext 里的 Job 和父级上下文里的不可能是通过一个实例,因为新的协程总会拿到一个 Job 的新实例
推荐阅读