0
点赞
收藏
分享

微信扫一扫

【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  StandaloneCoroutine{Active}@f30fe8 : DefaultDispatcher-worker-1
00:05:32.393 I StandaloneCoroutine{Active}@bc6a601 : DefaultDispatcher-worker-2

【Kotlin 协程】协程上下文 ( 协程上下文构成要素 | 指定协程上下文元素组合 | 协程上下文元素的继承关系 | 协程上下文元素的几种指定形式 | 默认 | 继承 | 自定义指定 )_协程






四、协程上下文元素的几种指定形式 ( 默认 | 继承 | 自定义指定 )


协程任务 的 协程上下文元素 由以下几种形式指定 :

  • ① 默认的 协程上下文 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 协程】协程上下文 ( 协程上下文构成要素 | 指定协程上下文元素组合 | 协程上下文元素的继承关系 | 协程上下文元素的几种指定形式 | 默认 | 继承 | 自定义指定 )_CoroutineContex_02


举报

相关推荐

【03】上下文

0 条评论