朱涛 · Kotlin 编程第一课
朱涛
Google 认证的 Kotlin、Android 开发者专家,博客“Kotlin Jetpack 实战”作者
6717 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
朱涛 · Kotlin 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

17 | Context:万物皆为Context?

你好,我是朱涛。今天我们来学习 Kotlin 协程的 Context。
协程的 Context,在 Kotlin 当中有一个具体的名字,叫做 CoroutineContext。它是我们理解 Kotlin 协程非常关键的一环。
从概念上讲,CoroutineContext 很容易理解,它只是个上下文而已,实际开发中它最常见的用处就是切换线程池。不过,CoroutineContext 背后的代码设计其实比较复杂,如果不能深入理解它的设计思想,那我们在后面阅读协程源码,并进一步建立复杂并发结构的时候,都将会困难重重。
所以这节课,我将会从应用的角度出发,带你了解 CoroutineContext 的使用场景,并会对照源码带你理解它的设计思路。另外,知识点之间的串联也是很重要的,所以我还会带你分析它跟我们前面学的 Job、Deferred、launch、async 有什么联系,让你能真正理解和掌握协程的上下文,并建立一个基于 CoroutineContext 的协程知识体系

Context 的应用

前面说过,CoroutineContext 就是协程的上下文。你在前面的第 14~16 讲里其实就已经见过它了。在第 14 讲我介绍 launch 源码的时候,CoroutineContext 其实就是函数的第一个参数:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Kotlin协程的Context是非常关键的一环,涉及到协程的上下文、线程切换等重要概念。本文从应用的角度出发,深入浅出地介绍了CoroutineContext的使用场景,并对比源码带领读者理解其设计思路。通过示例代码演示了如何使用CoroutineContext来指定协程工作的线程池,以及介绍了Kotlin官方提供的几种内置Dispatcher。此外,文章还强调了Dispatchers.Unconfined的特殊性,以及指出不应随意使用它。最后,文章强调了在Kotlin协程中,几乎所有重要的概念都与CoroutineContext有关,包括Job、Dispatcher、CoroutineExceptionHandler、CoroutineScope等。通过对CoroutineContext元素之间的关系的描述,帮助读者建立完整的知识体系。文章内容丰富,展示了CoroutineScope、Job和Dispatcher都是CoroutineContext的一种数据类型,且CoroutineScope是对CoroutineContext的进一步封装,其核心能力全部源自于CoroutineContext。总体而言,本文为读者提供了全面的了解和掌握Kotlin协程的Context,是一篇深入浅出的技术文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《朱涛 · Kotlin 编程第一课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • 神秘嘉Bin
    suspend方法需要在协程中执行,协程又一定有上下文,所以可以访问的到哈~ 也就是在suspend方法中可以访问当前协程上下文,并且拿到一些有用的信息

    作者回复: 很到位~

    2022-03-02
    13
  • 夜班同志
    挂起函数的Continuation就有CoroutineContext

    作者回复: 没错~

    2022-02-22
    10
  • 白泽丶
    如果为协程作用域创建时传入多个CoroutineContext,比如 Job() + Dispatcher.IO + Dispatcher.Main ,那么携程最终会在哪个线程池中执行呢

    作者回复: Dispatcher之间的组合其实并没有意义,你可以将其理解为后者替换前者。不过,在大部分情况下,IDE都会直接报错并告诉你:“Dispatcher之间的组合没有意义”。 ``` fun main() { // 报错 val scope = CoroutineScope(Dispatchers.IO + Dispatchers.Main) } ```

    2022-03-12
    4
    5
  • 白乾涛
    1、思考题中的方法为什么要加 suspend,加不加有什么区别吗? 2、为什么代码打印的都是 EmptyCoroutineContext,且没有 name? import kotlinx.coroutines.* import kotlinx.coroutines.GlobalScope.coroutineContext fun main() = runBlocking { printInfo(1) // 1 - EmptyCoroutineContext - null CoroutineScope(Dispatchers.IO + Job() + CoroutineName("bqt")).launch { printInfo(2) // 2 - EmptyCoroutineContext - null } delay(100L) } suspend fun printInfo(text: Any) = println("$text - $coroutineContext - ${coroutineContext[CoroutineName]?.name}")

    作者回复: import kotlin.coroutines.coroutineContext 导包的时候,不要弄错了。

    2022-02-26
    3
    5
  • 神秘嘉Bin
    如果你理解了第 14 讲的内容,那你一定能分析出它们的运行顺序应该是:1、4、2、3。 也有可能是1、2、4、3吧? 这个得看CPU的调度了,也有可能子协程的2线运行吧?

    作者回复: ``` fun main() = runBlocking { logX("Before launch.") // 1 launch { logX("In launch.") // 2 delay(1000L) logX("End launch.") // 3 } logX("After launch") // 4 } ``` 如果只针对这个案例,由于这里不涉及到多线程,所有协程都会运行在main之上,所以,我们基本上可以认为代码的执行顺序是这样的:1、4、2、3。 但如果涉及到多线程,则可能由于主线程繁忙,coroutine2在子线程先运行,而输出:1、2、4、3。 另外,如果我们配置其他的启动模式,或者其他的Context,则可能出现其他的代码运行顺序。

    2022-03-02
    2
    4
  • 7Promise
    思考题代码可以运行。coroutineContext方法是返回当前的CoroutineContext,因为runBlocking是CorouScope,CorouScope具有成员CoroutineContext,所以coroutineContext方法可以返回runBlocking的CoroutineContext。

    作者回复: 嗯,没错。

    2022-02-21
    3
  • 面无表情的生鱼片
    请教老师,经常看到 Job() + Dispatcher ,这么做是什么原因呢

    作者回复: 操作符重载你肯定能理解了对吧?至于Job() + Dispatcher的含义,其实就是同时指定:parentJob,还有线程池。

    2022-02-21
    2
    3
  • WWWarmFly
    请教老师, Dispatcher 内部成员的类型是CoroutineContext,这里怎么推出 Dispatcher 确实就是 CoroutineContext

    作者回复: 这样的关系:Dispatcher - CoroutineContext.Element - CoroutineContext

    2022-03-20
    2
  • Shanks-王冲
    Kotlin1.6源码package kotlin.coroutines中找到了这个,public suspend inline val coroutineContext: CoroutineContext,成员定义成suspend了,我不知道该怎么解释,贴出试试

    作者回复: 没错,方向是对的,这就是我希望你们去看的coroutineContext变量,你可以再想想它的作用吗? PS:具体答案我会在第27讲里给出的。

    2022-03-17
    1
  • Renext
    代码段6报错: Cannot access 'ExecutorCoroutineDispatcherImpl': it is private in file

    作者回复: ExecutorService.asCoroutineDispatcher()是Kotlin的源码哈,不需要你写进工程里的。

    2022-03-08
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部