使用 launch 或 async 协程构建器 启动 协程时 , 都要 指定一个 协程上下文 , 如果没有指定 , 则使用默认的 空的协程上下文 EmptyCoroutineContext ;
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
协程上下文 CoroutineContext : 是用于定义 协程行为 的一组数据 , 其包含了如下内容 :
协程上下文 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 , 在协程上下文 中 不同元素 有不同的 继承形式 ;
协程上下文 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
协程任务 的 协程上下文元素 由以下几种形式指定 :
" coroutine "
;// 将主线程包装成协程
runBlocking<Unit>{
launch(){
Log.i(TAG, "当前运行的线程 : ${Thread.currentThread().name}")
}
}
// 将主线程包装成协程
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