Kotlin 协程协程上下文 ( 协程上下文构成要素 | 指定协程上下文元素组合 | 协程上下文元素的继承关系 | 协程上下文元素的几种指定形式 | 默认 | 继承 | 自定义指定 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 协程协程上下文 ( 协程上下文构成要素 | 指定协程上下文元素组合 | 协程上下文元素的继承关系 | 协程上下文元素的几种指定形式 | 默认 | 继承 | 自定义指定 )相关的知识,希望对你有一定的参考价值。
文章目录
一、协程上下文构成要素
使用 launch 或 async 协程构建器 启动 协程时 , 都要 指定一个 协程上下文 , 如果没有指定 , 则使用默认的 空的协程上下文 EmptyCoroutineContext ;
- 下面是 launch 协程构建器的原型 : 第一个参数 协程上下文 CoroutineContext 默认为 EmptyCoroutineContext ;
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
- 下面是 async 协程构建器的原型 : 第一个参数 协程上下文 CoroutineContext 默认为 EmptyCoroutineContext ;
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
协程上下文 CoroutineContext : 是用于定义 协程行为 的一组数据 , 其包含了如下内容 :
- 协程任务 Job : 用于 控制协程生命周期 ;
- 协程调度器 CoroutineDispatcher : 用于 分发协程任务 , 被调度主体是 线程 , 也就是安排哪个线程执行哪个任务 ;
- 协程名称 CoroutineName : 在调试协程程序时 , 可以通过协程名称 分辨协程 ;
- 协程异常处理器 CoroutineExceptionHandler : 用于处理协程中 未被捕获的异常 ;
二、指定协程上下文元素组合
协程上下文 CoroutineContext 类 , 进行了运算符重载 , 如下为重载内容 :
/**
* 返回一个包含来自此上下文和来自其他[context]的元素的上下文。
* 该上下文中与另一个上下文中具有相同键的元素将被删除。
*/
public operator fun plus(context: CoroutineContext): CoroutineContext =
if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation
context.fold(this) acc, element ->
val removed = acc.minusKey(element.key)
if (removed === EmptyCoroutineContext) element else
// make sure interceptor is always last in the context (and thus is fast to get when present)
val interceptor = removed[ContinuationInterceptor]
if (interceptor == null) CombinedContext(removed, element) else
val left = removed.minusKey(ContinuationInterceptor)
if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else
CombinedContext(CombinedContext(left, element), interceptor)
因此 , 可以使用 +
运算符拼装协程 ;
代码示例 :
// 将主线程包装成协程
runBlocking<Unit>
launch(
// 为 协程上下文 指定 协程调度器 + 协程名称 两个元素
Dispatchers.Default + CoroutineName("Hello")
)
Log.i(TAG, "当前运行的线程 : $Thread.currentThread().name")
使用 +
运算符 , 为协程上下文 CoroutineContext 指定
- 协程调度器
Dispatchers.Default
- 协程名称
CoroutineName("Hello")
三、协程上下文元素的继承关系
协程上下文元素的继承 : 在 线程 / 协程 中 可以 创建协程 , 创建协程时 , 需要设置 协程上下文 CoroutineContext , 在协程上下文 中 不同元素 有不同的 继承形式 ;
- 协程任务 Job , 是全新的 ;
- 协程调度器 CoroutineDispatcher | 协程名称 CoroutineName | 协程异常处理器 CoroutineExceptionHandler 三个元素会从 协程上下文 CoroutineContext 父类 继承 ;
协程上下文 CoroutineContext 父类 , 示例 :
在 协程 A 中 创建 协程 B , 则
协程 A 的 协程上下文 CoroutineContext
就是
协程 B 的 协程上下文 CoroutineContext
的 父类 ;
代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
class MainActivity : AppCompatActivity()
val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 将主线程包装成协程
runBlocking<Unit>
// 创建协程作用域
// 协程 1
val coroutineScope = CoroutineScope(Job() + Dispatchers.Default + CoroutineName("Hello"))
// 协程 2
val job2 = coroutineScope.launch()
// coroutineContext[Job] 可以获取 协程上下文的 Job 元素
Log.i(TAG, "$coroutineContext[Job] : $Thread.currentThread().name")
// 协程 3
val job3 = launch
Log.i(TAG, "$coroutineContext[Job] : $Thread.currentThread().name")
// 等待 job3 任务执行完毕
job3.join()
// 等待 job2 执行完毕
job2.join()
// 协程 1 是 协程 2 的父类协程
// 协程 2 是 协程 3 的父类协程
执行结果 : 协程任务 Job 是不同的 ; 协程调度器都是 DefaultDispatcher ;
00:05:32.391 I StandaloneCoroutineActive@f30fe8 : DefaultDispatcher-worker-1
00:05:32.393 I StandaloneCoroutineActive@bc6a601 : DefaultDispatcher-worker-2
四、协程上下文元素的几种指定形式 ( 默认 | 继承 | 自定义指定 )
协程任务 的 协程上下文元素 由以下几种形式指定 :
- ① 默认的 协程上下文 CoroutineContext : 下面代码中 launch 构建的协程就是默认参数 ;
- 默认 协程调度器 CoroutineDispatcher : Dispatchers.Default ;
- 默认 协程名称 CoroutineName :
" coroutine "
;
// 将主线程包装成协程
runBlocking<Unit>
launch()
Log.i(TAG, "当前运行的线程 : $Thread.currentThread().name")
- ② 继承自父类的 协程上下文 CoroutineContext : 继承自 父协程 或 CoroutineScope 的 协程上下文 ; 参考 " 三、协程上下文元素的继承关系 " 中的示例 ;
- ③ 自定义的 协程上下文 CoroutineContext 元素参数 : 在 协程构建器 中指定的 协程上下文参数 优先级最高 , 可以 覆盖 默认值 和 继承自父类的 协程上下文元素 , 如下代码示例 ;
// 将主线程包装成协程
runBlocking<Unit>
launch(
// 为 协程上下文 指定 协程调度器 + 协程名称 两个元素
Dispatchers.Default + CoroutineName("Hello")
)
Log.i(TAG, "当前运行的线程 : $Thread.currentThread().name")
完整代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
class MainActivity : AppCompatActivity()
val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 将主线程包装成协程
runBlocking<Unit>
// 协程异常处理器
val coroutineExceptionHandler = CoroutineExceptionHandler
coroutineContext, throwable ->
Log.i(TAG, "处理协程异常 : $throwable")
// 创建协程作用域
// 协程 1
val coroutineScope = CoroutineScope(
Job() + // 协程任务
Dispatchers.Main + // 协程调度器
CoroutineName("Hello") + // 协程名称
coroutineExceptionHandler // 协程异常处理器
)
// 协程 2
// 在 CoroutineScope 中创建 子协程 ,
// 其协程上下文都继承自 coroutineScope 的协程上下文
val job2 = coroutineScope.launch(Dispatchers.IO)
// 通过线程查看协程调度器
Log.i(TAG, "$Thread.currentThread().name")
// 协程 3
// 在 job2 协程中创建 子协程 ,
// 其协程上下文都继承自 job2 的协程上下文
val job3 = launch()
// 通过线程查看协程调度器 , 该协程的 协程调度器 是 Dispatchers.IO
Log.i(TAG, "$Thread.currentThread().name")
// 等待 job3 任务执行完毕
job3.join()
// 等待 job2 执行完毕
job2.join()
// 协程 1 是 协程 2 的父类协程
// 协程 2 是 协程 3 的父类协程
执行结果 :
00:34:00.217 I DefaultDispatcher-worker-1
00:34:00.217 I DefaultDispatcher-worker-3
以上是关于Kotlin 协程协程上下文 ( 协程上下文构成要素 | 指定协程上下文元素组合 | 协程上下文元素的继承关系 | 协程上下文元素的几种指定形式 | 默认 | 继承 | 自定义指定 )的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 协程协程异常处理 ③ ( 协程异常处理器 CoroutineExceptionHandler 捕获异常 | 验证 CoroutineScope 协程的异常捕捉示例 )
Kotlin 协程协程异常处理 ③ ( 协程异常处理器 CoroutineExceptionHandler 捕获异常 | 验证 CoroutineScope 协程的异常捕捉示例 )
深入理解Kotlin协程协程的上下文 CoroutineContext
Kotlin 协程协程底层实现 ① ( Kotlin 协程分层架构 | 基础设施层 | 业务框架层 | 使用 Kotlin 协程基础设施层标准库 Api 实现协程 )
Kotlin 协程协程底层实现 ① ( Kotlin 协程分层架构 | 基础设施层 | 业务框架层 | 使用 Kotlin 协程基础设施层标准库 Api 实现协程 )