Kotlin协程(二)协程的生命周期及管理
在 Kotlin 中,协程的生命周期 主要涉及 创建(Starting)、执行(Active)、挂起(Suspended)、取消(Cancelled) 和 完成(Completed) 这些状态。协程的生命周期受 CoroutineScope 和 Job 控制。
1. 协程的生命周期状态
Kotlin 协程的生命周期可以分为以下几个阶段:
🔹 1.1 新建(New)
- 调用
launch
或async
创建协程,但协程还未执行。 - 示例
val job = GlobalScope.launch {
// 协程代码
}
🔹 1.2 运行(Active)
-
协程开始执行,进入 Active 状态。
-
这包括:
- 立即执行的协程(默认情况下,
launch
立即执行) - 被恢复的协程(例如
delay
结束后恢复)
- 立即执行的协程(默认情况下,
val job = GlobalScope.launch {
println("协程开始执行") // Active
}
🔹 1.3 挂起(Suspended)
-
协程执行
delay()
、suspend fun
等操作,暂停执行,不会阻塞线程。 -
之后可以恢复执行。
val job = GlobalScope.launch {
println("协程启动")
delay(2000) // 挂起
println("协程恢复")
}
🔹 1.4 取消(Cancelling)
-
job.cancel()
取消协程,进入 Cancelling 状态,随后变成 Cancelled。 -
需要 检查
isActive
或使用ensureActive()
避免取消后继续执行。
val job = GlobalScope.launch {
repeat(100) { i ->
if (!isActive) return@launch // 取消检查
println("运行中:$i")
delay(500)
}
}
delay(2000)
job.cancel() // 取消协程
🔹 1.5 完成(Completed)
-
协程正常执行完毕,变为 Completed 状态。
val job = GlobalScope.launch {
println("任务完成")
}
job.invokeOnCompletion {
println("协程结束")
}
等待子协程
+-----+ start +--------+ complete +-------------+ finish +-----------+
| 新建 | -----> | Active | --------> | Completing | -------> | 已完成 |
+-----+ +--------+ +-------------+ +-----------+
| 取消 / 失败 |
| +----------------+
| |
V V
+------------+ 完成 +-----------+
| 取消中 | --------------------------------> | 已取消 |
+------------+ +-----------+
2. 协程生命周期管理
2.1 通过 Job
监听状态
val job = GlobalScope.launch {
delay(1000)
println("任务完成")
}
println(job.isActive) // true(运行中)
println(job.isCompleted) // false
println(job.isCancelled) // false
job.cancel()
println(job.isCancelled) // true
2.2 通过 invokeOnCompletion
监听完成状态
val job = GlobalScope.launch {
delay(1000)
println("任务完成")
}
job.invokeOnCompletion { cause ->
if (cause == null) {
println("协程成功完成")
} else {
println("协程被取消,原因:$cause")
}
}
job.cancel()
3. 不同 CoroutineScope
影响生命周期
CoroutineScope | 说明 | 生命周期 |
---|---|---|
GlobalScope | 应用级作用域,协程与进程同生命周期 | 进程结束时才取消 |
CoroutineScope | 自定义作用域,需要手动取消 | 作用域内有效 |
viewModelScope | 适用于 ViewModel ,随 ViewModel 销毁而取消 | ViewModel 结束时取消 |
lifecycleScope | 适用于 Activity /Fragment ,随生命周期变化 | Activity/Fragment 结束时取消 |
4. Job.cancel()
vs Job.cancelAndJoin()
-
job.cancel()
立即取消,不会等待子协程完成。 -
job.cancelAndJoin()
取消后等待协程完全结束。
val job = GlobalScope.launch {
repeat(100) { i ->
println("运行中:$i")
delay(500)
}
}
delay(2000)
job.cancelAndJoin() // 确保协程完全结束
println("协程已取消")
cancelAndJoin():
这里 "协程已取消"
一定在协程结束后才会打印,不会有 "运行中:4"
出现。
🔹使用cancel() "协程已取消"
可能在日志中提前出现?
运行中:0
运行中:1
运行中:2
运行中:3
协程已取消
运行中:4 // 可能仍然出现
运行中:5 // 可能仍然出现
...
cancel()
只是请求取消,但println("协程已取消")
不等待协程真的结束,主线程会立即继续执行。- 如果协程未及时检查
isActive
或执行delay()
,可能会继续运行一段时间。
总结
- 协程的生命周期状态:
New
→Active
→Suspended
→Cancelled
→Completed
- 管理协程状态:使用
Job
控制isActive
、cancel()
以及invokeOnCompletion()
- 选择合适的 CoroutineScope:如
viewModelScope
适用于 ViewModel - 避免内存泄漏:在 Activity/Fragment 销毁时取消协程