Kotlin 中的协程上下文(Coroutine Context)是协程运行时的一个关键概念,它定义了协程的执行环境,包括调度器(dispatcher)、异常处理器、Job 等。掌握协程上下文对于理解协程的运行机制、控制协程的生命周期和调度行为非常重要。
一、什么是协程上下文(CoroutineContext)
CoroutineContext
是一个接口,它的实现是一个键值对的集合。Kotlin 协程中的每个协程都运行在一个协程上下文中,协程上下文定义了协程的行为和调度方式。
协程上下文可以包含如下元素:
元素类型 | 说明 |
---|---|
Job |
协程的生命周期管理,支持取消、父子协程关系等 |
CoroutineDispatcher |
协程调度器,决定在哪个线程或线程池中运行代码 |
CoroutineName |
协程的名字,便于调试 |
CoroutineExceptionHandler |
处理协程中的未捕获异常 |
二、常见上下文元素
1. Job
- 表示协程的生命周期,可以控制其启动、取消、完成。
- 每个协程默认都会关联一个
Job
。
val job = Job()
val scope = CoroutineScope(job)
2. CoroutineDispatcher
控制协程代码在哪个线程或线程池中执行。
-
常见的调度器有:
-
Dispatchers.Default
:适用于 CPU 密集型任务 -
Dispatchers.IO
:适用于 I/O 密集型任务 -
Dispatchers.Main
:主线程,用于 Android UI 操作 -
Dispatchers.Unconfined
:不限制线程,通常用于调试或特定场景
-
launch(Dispatchers.IO) {
// 运行在 IO 线程
}
3. CoroutineName
- 给协程起名字,方便调试日志查看。
val context = CoroutineName("MyCoroutine")
launch(context) {
println(coroutineContext[CoroutineName])
}
4. CoroutineExceptionHandler
- 处理协程中未捕获的异常(仅对 根协程 生效)。
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught exception: $exception")
}
GlobalScope.launch(handler) {
throw RuntimeException("Test exception")
}
三、组合协程上下文
协程上下文可以通过 +
操作符组合多个元素:
val context = Dispatchers.IO + CoroutineName("IOWorker") + Job()
val scope = CoroutineScope(context)
注意:协程上下文中,相同类型的元素只能存在一个,后加的会替换前面的。
四、如何获取当前协程的上下文
可以使用 coroutineContext
来获取当前协程的上下文:
launch {
println("Current dispatcher: ${coroutineContext[CoroutineDispatcher]}")
println("Current job: ${coroutineContext[Job]}")
}
五、协程作用域中的上下文
-
CoroutineScope
是协程的生命周期容器,内部包含一个协程上下文。 - 使用
launch
,async
时默认继承父协程的上下文,也可以添加新的元素:
val scope = CoroutineScope(Dispatchers.Default + CoroutineName("MainScope"))
scope.launch {
println("Coroutine name: ${coroutineContext[CoroutineName]}")
}
六、应用场景举例(Android)
class MyViewModel : ViewModel() {
private val vmScope = viewModelScope
fun loadData() {
vmScope.launch(Dispatchers.IO + CoroutineName("LoadData")) {
try {
val data = repository.loadFromNetwork()
withContext(Dispatchers.Main) {
// 更新 UI
}
} catch (e: Exception) {
Log.e("CoroutineError", "Exception: $e")
}
}
}
}
总结
概念 | 用途 |
---|---|
CoroutineContext |
协程运行时的环境 |
Job |
控制协程生命周期 |
Dispatcher |
控制在哪个线程或线程池运行 |
CoroutineName |
协程命名,方便调试 |
ExceptionHandler |
捕获协程中的未处理异常 |
注释From AIKotlin 中的协程上下文(Coroutine Context)是协程运行时的一个关键概念,它定义了协程的执行环境,包括调度器(dispatcher)、异常处理器、Job 等。掌握协程上下文对于理解协程的运行机制、控制协程的生命周期和调度行为非常重要。
一、什么是协程上下文(CoroutineContext)
CoroutineContext
是一个接口,它的实现是一个键值对的集合。Kotlin 协程中的每个协程都运行在一个协程上下文中,协程上下文定义了协程的行为和调度方式。
协程上下文可以包含如下元素:
元素类型 | 说明 |
---|---|
Job |
协程的生命周期管理,支持取消、父子协程关系等 |
CoroutineDispatcher |
协程调度器,决定在哪个线程或线程池中运行代码 |
CoroutineName |
协程的名字,便于调试 |
CoroutineExceptionHandler |
处理协程中的未捕获异常 |
二、常见上下文元素
1. Job
- 表示协程的生命周期,可以控制其启动、取消、完成。
- 每个协程默认都会关联一个
Job
。
val job = Job()
val scope = CoroutineScope(job)
2. CoroutineDispatcher
控制协程代码在哪个线程或线程池中执行。
-
常见的调度器有:
-
Dispatchers.Default
:适用于 CPU 密集型任务 -
Dispatchers.IO
:适用于 I/O 密集型任务 -
Dispatchers.Main
:主线程,用于 Android UI 操作 -
Dispatchers.Unconfined
:不限制线程,通常用于调试或特定场景
-
launch(Dispatchers.IO) {
// 运行在 IO 线程
}
3. CoroutineName
- 给协程起名字,方便调试日志查看。
val context = CoroutineName("MyCoroutine")
launch(context) {
println(coroutineContext[CoroutineName])
}
4. CoroutineExceptionHandler
- 处理协程中未捕获的异常(仅对 根协程 生效)。
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught exception: $exception")
}
GlobalScope.launch(handler) {
throw RuntimeException("Test exception")
}
三、组合协程上下文
协程上下文可以通过 +
操作符组合多个元素:
val context = Dispatchers.IO + CoroutineName("IOWorker") + Job()
val scope = CoroutineScope(context)
注意:协程上下文中,相同类型的元素只能存在一个,后加的会替换前面的。
四、如何获取当前协程的上下文
可以使用 coroutineContext
来获取当前协程的上下文:
launch {
println("Current dispatcher: ${coroutineContext[CoroutineDispatcher]}")
println("Current job: ${coroutineContext[Job]}")
}
五、协程作用域中的上下文
-
CoroutineScope
是协程的生命周期容器,内部包含一个协程上下文。 - 使用
launch
,async
时默认继承父协程的上下文,也可以添加新的元素:
val scope = CoroutineScope(Dispatchers.Default + CoroutineName("MainScope"))
scope.launch {
println("Coroutine name: ${coroutineContext[CoroutineName]}")
}
六、应用场景举例(Android)
class MyViewModel : ViewModel() {
private val vmScope = viewModelScope
fun loadData() {
vmScope.launch(Dispatchers.IO + CoroutineName("LoadData")) {
try {
val data = repository.loadFromNetwork()
withContext(Dispatchers.Main) {
// 更新 UI
}
} catch (e: Exception) {
Log.e("CoroutineError", "Exception: $e")
}
}
}
}
总结
概念 | 用途 |
---|---|
CoroutineContext |
协程运行时的环境 |
Job |
控制协程生命周期 |
Dispatcher |
控制在哪个线程或线程池运行 |
CoroutineName |
协程命名,方便调试 |
ExceptionHandler |
捕获协程中的未处理异常 |