![](/style/images/good.png)
![](/style/images/bad.png)
你不知道的CoroutineContext:协程上下文大揭秘!
source link: http://www.rousetime.com/2024/01/06/%E4%BD%A0%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84CoroutineContext%EF%BC%9A%E5%8D%8F%E7%A8%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E5%A4%A7%E6%8F%AD%E7%A7%98%EF%BC%81/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
你不知道的CoroutineContext:协程上下文大揭秘!
协程(Coroutine)是一种并发编程技术,它允许我们在一个线程中执行多个任务,而不需要创建多个线程。协程与线程的区别在于,线程是操作系统的概念,而协程是编程语言的概念。协程可以暂停和恢复执行,而线程只能被终止。
在 Android 中,协程由 Kotlin 语言支持。Kotlin 协程库提供了丰富的 API,可以帮助我们轻松地编写并发代码。其中,CoroutineContext
是一个非常重要的概念,它定义了协程的执行环境。
在本篇文章中,我们将从以下几个方面来介绍CoroutineContext
的工作原理:
CoroutineContext
的概念CoroutineContext
的组成CoroutineContext
的继承CoroutineContext
的注意事项
CoroutineContext的概念
CoroutineContext是一个容器,它包含了协程的所有上下文信息。这些上下文信息包括:
- 协程的状态:协程的状态表示协程的生命周期。协程可以处于 Active、Completed、Canceled 等状态。
- 协程的调度策略:协程的调度策略决定了协程在哪里执行。协程可以执行在主线程、后台线程、或其他协程池中。
- 协程的标签:协程的标签用于标识协程。
- 协程的拦截器:协程的拦截器用于拦截协程的执行流程。
- 协程的异常捕获:用于处理协程内部发生的未捕获异常。
CoroutineContext可以通过 coroutineContext
获取。
fun main() = runBlocking {
val context = coroutineContext
println(context)
}
[CoroutineId(2), "coroutine#2":BlockingCoroutine{Active}@769c9116, BlockingEventLoop@6aceb1a5]
CoroutineContext的组成
CoroutineContext由多个组件组成,这些组件可以通过 context.get<T>()
函数来获取。
public operator fun <E : Element> get(key: Key<E>): E?
由于重新定义了get
操作符,所以可以直接使用context[key]
来获取对应的上下文组件元素。
- Dispatcher:协程的调度策略。
fun main() = runBlocking {
val context = coroutineContext + Dispatchers.Main
val dispatcher = context[CoroutineDispatcher]
println(dispatcher)
}
Dispatchers.Main[missing]
- Job:协程的状态。Job 表示协程的生命周期。
fun main() = runBlocking {
val context = coroutineContext + SupervisorJob()
val job = context[Job]
println(job)
}
SupervisorJobImpl{Active}@50675690
- 获取协程的状态:协程的状态表示协程的生命周期。协程可以处于 Active、Completed、Canceled 等状态。
fun main() = runBlocking {
val context = coroutineContext + SupervisorJob()
// 获取协程的状态
val job = context[Job]
// 判断协程是否处于 Active 状态
if (job?.isActive == true) {
println("协程处于 Active 状态")
}
}
协程处于 Active 状态
- CoroutineName:协程的标签。CoroutineName 用于标识协程。
fun main() = runBlocking {
val context = coroutineContext + CoroutineName("张三")
val coroutineName = context[CoroutineName]
println(coroutineName)
}
CoroutineName(张三)
- 添加拦截器:拦截器可以拦截协程的执行流程,例如:
- 在协程开始执行之前进行一些初始化操作。
- 在协程执行期间进行一些监控操作。
- 在协程执行完成之后进行一些清理操作。
class MyContinuationInterceptor : ContinuationInterceptor {
override fun interceptContinuation(continuation: Continuation<Unit>): Continuation<Unit> {
// 在协程开始执行之前进行一些初始化操作
println("MyContinuationInterceptor: 协程开始执行之前")
// 返回原始的 continuation
return continuation
}
override fun key(): CoroutineContext.Key<ContinuationInterceptor> = ContinuationInterceptor.Key
}
fun main() {
// 启动一个协程
launch(Dispatchers.IO + MyContinuationInterceptor()) {
// 执行一些耗时操作
delay(1000)
}
}
在这个示例中,协程在开始执行之前会打印一条消息:
MyContinuationInterceptor: 协程开始执行之前
- CoroutineExceptionHandler:处理协程内部发生的未捕获异常
import kotlinx.coroutines.*
fun main() {
// 创建CoroutineExceptionHandler
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught an exception: $exception")
}
// 启动一个协程,并指定CoroutineExceptionHandler
runBlocking {
val context = coroutineContext + exceptionHandler
val job = GlobalScope.launch(context) {
// 模拟一个可能抛出异常的操作
println("Coroutine is doing some work")
delay(1000)
throw CustomException("Something went wrong!")
}
// 等待协程执行结束
job.join()
}
}
// 自定义异常类
class CustomException(message: String) : Exception(message)
在这个示例中,为原有的coroutineContext
增加了捕获异常的exceptionHandler
,以至于协程内容抛出异常时,会被CoroutineExceptionHandler
所捕获。
使用CoroutineExceptionHandler
的好处在于,你可以集中处理协程内部的所有异常,而不必在每个协程体中都使用try-catch
块来捕获异常。
- EmptyCoroutineContext:一个空的 CoroutineContext。
CoroutineContext的继承
CoroutineContext
支持继承。子CoroutineContext
可以继承父CoroutineContext
的所有组件。
fun main() = runBlocking {
val parentContext = coroutineContext + Dispatchers.Main + SupervisorJob() + CoroutineName("张三")
val childContext = parentContext + Dispatchers.IO
println(childContext)
}
[CoroutineId(2), SupervisorJobImpl{Active}@1b40d5f0, CoroutineName(张三), Dispatchers.IO]
在这个例子中,parentContext
包含 Dispatchers.Main
、Job()
和CoroutineName("张三")
,childContext
继承了 parentContext
的所有组件,并添加了 Dispatchers.IO
,由于与Dispatchers.Main
同为调度器,所以最终保留的是最后的Dispatchers.IO
。
CoroutineContext的注意事项
在使用CoroutineContext
时,需要注意以下几点:
- 合理选择调度器:根据任务的性质选择合适的调度器,避免在IO密集型任务中使用CPU密集型的调度器,以及反之。
- 细致管理CoroutineContext:合理管理CoroutineContext的元素,不要过度添加不必要的元素,以免引起不必要的性能开销。
- 异常处理:及时处理协程中的异常,可以通过在CoroutineContext中添加CoroutineExceptionHandler元素来实现。
总而言之,CoroutineContext
是协程的一个重要概念。充分理解CoroutineContext
的工作原理和使用方法,这样才能更好地利用CoroutineContext
来控制协程的执行。
android_startup: 提供一种在应用启动时能够更加简单、高效的方式来初始化组件,优化启动速度。不仅支持Jetpack App Startup的全部功能,还提供额外的同步与异步等待、线程控制与多进程支持等功能。
AwesomeGithub: 基于Github的客户端,纯练习项目,支持组件化开发,支持账户密码与认证登陆。使用Kotlin语言进行开发,项目架构是基于JetPack\&DataBinding的MVVM;项目中使用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技术。
flutter_github: 基于Flutter的跨平台版本Github客户端,与AwesomeGithub相对应。
android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 帮助读者能够更快的掌握与理解所阐述的要点。
daily_algorithm: 每日一算法,由浅入深,欢迎加入一起共勉。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK