1. 概述

挂起函数是Kotlin协程最重要的一个特性,所有其他概念都建立在它的基础上。所以我们需要深入了解它的工作原理。

挂起协程意味着在中间停止它。这类似于玩游戏,当我们想暂停游戏时,可以先存档,想继续游戏时,可以从存档处恢复游戏。当协程被暂停时,它会返回一个Continuation. 这就像游戏中的存档,协程可以使用Continuation从挂起的地方恢复。

请注意,这与线程非常不同,线程无法保存,只能阻塞。协程要强大得多,挂起时,它不消耗任何所在线程的资源。协程不一定需要在启动协程的线程上恢复,可以切换到不同的线程上。

2. 恢复

让我们看看它的实际效果。我们使用协程构建器(如runBlocking或launch)启动协程。suspend函数是可以挂起协程的函数。这意味着,它们必须在协程(或另一个挂起函数)上调用。

这是一个简单的程序,将打印“Before”和“After”。如果我们在中间调用协程标准库提供的suspendCoroutine函数会怎样呢?

如果你执行上面的代码,你将发现不会打印“After”,并且main函数不会退出。协程在“Before”之后暂停。我们的程序停止了,再也没有恢复。那我们怎么做呢?我们可以使用Continuation来恢复程序?

我们观察下suspendCoroutine调用,注意它以 lambda 表达式 ( { })结尾。作为参数传递的函数将在暂停之前被调用。此函数将Continuation作为参数。

观察打印日志,我们发现“After”仍然没有打印。我们可以用Continuation的resume方法让协程恢复执行。

请注意,上面示例中的“After”被打印出来,因为我们在suspendCoroutine中调用resume函数。

从 Kotlin 1.3 开始, Continuation的定义发生了变化。resumeWith函数代替了resume和resumeWithException函数。我们使用的resume和resumeWithException是标准库中的扩展函数。

我们还可以使用它来启动一个不同的线程,该线程将休眠一段时间后恢复:

我们还可以将启动线程的代码提取到一个函数中。

这种机制是有效的,但是我们也可以用线程池来代替线程。


暂停一段时间似乎是一个有用的功能。让我们把它提取成一个函数。我们将命名它delay。

这正是Kotlin协程库delay方法曾经的实现方式。目前的实现比较复杂,主要是为了支持测试,但是本质思路还是一样的。

3. 带值恢复

您可能需要注意的是我们为什么将Unit传递给resume函数,为什么我们将Unit作为suspendCoroutine函数泛型类型。Unit是suspendCoroutine函数的返回类型,也是Continuation的泛型类型。

当我们调用suspendCoroutine时,我们可以指定Continuation中的返回类型。resume函数需要调用与之相同的类型。

挂起对协程非常有意义。当我们做耗时操作时,我们需要被挂起。例如,当我们需要从API获取网络响应时,如果没有协程,这个线程就需要等待。因为线程很昂贵,这将是一个巨大的浪费。特别是当这是一个重要的线程,比如 Android 上的主线程。使用协程,它只是挂起协程,然后线程可以去做其他事情。一旦数据到了,线程将从协程挂起点恢复。

举个例子,我们模拟网络请求用户信息:


直接在main方法中调用suspendCoroutine不太方便。我们可以把它提取成一个方法。

目前,许多流行的库如Retrofit或Room已经支持suspend函数。这就是为什么我们很少需要在suspend函数中使用回调函数的原因。还有一个和suspendCoroutine类似的方法suspendCancellableCoroutine,我推荐你使用后者,后者支持取消功能。

你可能想知道如果API不给我们数据而是返回异常会怎样。如果服务死机或响应错误会怎样?。在这种情况下,我们不能返回数据,而是应该从协程挂起的地方抛出异常

4. 异常恢复

我们调用的每个函数都可能返回某个值或抛出异常。对于suspendCoroutine也是如此。我们可以调用resumeWithException从异常处返回。可以用try catch捕获异常。

5. 挂起一个协程,而不是一个函数

需要强调的一件事是我们只是暂停了一个协程,而不是一个函数。想象一下,我们将Continuation存储在某个变量中,并尝试在函数调用后恢复它。


这没有任何意义。resume永远不会被调用。

欢迎关注"字节小站"同名微信公众号。

深入理解Kotlin协程suspend工作原理(初学者也能看得懂)相关推荐

  1. pdf 深入理解kotlin协程_Kotlin协程实现原理:挂起与恢复

    今天我们来聊聊Kotlin的协程Coroutine. 如果你还没有接触过协程,推荐你先阅读这篇入门级文章What? 你还不知道Kotlin Coroutine? 如果你已经接触过协程,但对协程的原理存 ...

  2. pdf 深入理解kotlin协程_协程初探

    Hello,各位朋友,小笨鸟我回来了! 近期学习了Kotlin协程相关的知识,感觉这块技术在项目中的可应用性很大,对项目的开发效率和维护成本有较大的提升.于是就考虑深入研究下相关概念和使用方式,并引入 ...

  3. 【深入理解Kotlin协程】Google的工程师们是这样理解Flow的?

    Question:why there is a Flow in kotlin? 问这个问题就好比在问为什么那里会有一座山存在,嗯,这貌似是一个哲学问题.当然,对于kotlin中的Flow的理解可能不会 ...

  4. pdf 深入理解kotlin协程_深入理解Kotlin协程

    领取成功 您已领取成功! 您可以进入Android/iOS/Kindle平台的多看阅读客户端,刷新个人中心的已购列表,即可下载图书,享受精品阅读时光啦! - | 回复不要太快哦~ 回复内容不能为空哦 ...

  5. Kotlin协程:挂起与恢复原理逆向刨析

    前言:只有在那崎岖的小路上不畏艰险奋勇攀登的人,才有希望达到光辉的顶点. --马克思 前言 经过前面两篇协程的学习,我相信大家对协程的使用已经非常熟悉了.本着知其然更要知其之所以然的心态,很想知道它里 ...

  6. 一文看透 Kotlin 协程本质

    前言 公司开启新项目了,想着准备亮一手 Kotlin 协程应用到项目中去,之前有对 Kotlin 协程的知识进行一定量的学习,以为自己理解协程了,结果--实在拿不出手! 为了更好的加深记忆和理解,更全 ...

  7. 枯燥的Kotlin协程三部曲(上)——概念启蒙篇

    0x0.引言 Kotlin 1.3 版本开始引入协程 Coroutine,简练的官方文档和网上一堆浅尝辄止的文章让我心里有些没底,不想止步于仅仅知道: ① Android中,Kotlin协程用于解决: ...

  8. 在 Android 开发中使用 Kotlin 协程 (一) -- 初识 Kotlin 协程

    前言 最近在研究 Kotlin 协程,发现功能真的超级强大,很有用,而且很好学,如果你正在或计划使用 Kotlin 开发 Android,那么 Kotlin 协程你一定不能错过! 协程是什么? 我们平 ...

  9. 分析Kotlin协程只挂起不恢复会怎样(是否存在协程泄漏),以及挂起的协程存在哪里?

    前言 刚开始正式学协程原理的时候(以前只是学api怎么用),大概是20年6月,也就是bennyhuo大佬出书<深入理解Kotlin协程>的时候,我买了本然后细细研究,我的内心就一直有一个问 ...

最新文章

  1. C#精髓 第四讲 GridView 72般绝技
  2. Java字节码instrument研究
  3. iOS系统网络抓包方法
  4. [IIS] [PHP] 500.19 随机出现
  5. @Aspect注解无效
  6. 自定义idea archetype
  7. bootstrap-table 新增可编辑行_现代Web开发堆栈工具DevExtreme 新增Gantt组件,助力项目管理...
  8. 基于Kmeans算法的文档聚类(包含Java代码及数据格式)
  9. 实体类里的内部类怎么单独赋值_java你还在用各种setter赋值初始对象吗?用设计模式化简为易...
  10. mysql error 1790_Mysql 数据恢复报错
  11. 中国制盐市场销售动态及需求潜力预测报告(新版)2022-2027年
  12. 高通平台fastboot下载
  13. (华师2021年秋季课程作业以及答案3)论述东西方文化差异对建筑风格的影响。
  14. 运维(6) Nacos开启连接密码安全认证
  15. 艾永亮:产品创新的重要性,创新的意义和思路
  16. fdisk:Linux 下管理磁盘分区的利器
  17. 《般若波罗蜜多心经》注解
  18. GitHub下载代理设置
  19. 计算各种面值人民币张数
  20. URLDownloadToFile缓存问题

热门文章

  1. C++学习笔记 C++11 std::chrono知识
  2. 电脑版微信怎么双开、多开 超级简单
  3. nacos界面定制化
  4. 计算机怎样发现路由器上u盘,路由器USB插口的4个功能,你也许一个都不知道!...
  5. 微信支付服务商,![CDATA[sub_mch_id与sub_appid不匹配],微信小程序支付,签名错误,CDATA[签名错误]解决方法,支付签名验证失败
  6. HTML5 canvas 行星环绕
  7. 如何编辑制作并发送手机报?
  8. 闲谈IPv6-IPv6地址聚类分配原则于源地址选择的关系
  9. Elasticsearch:如何在 Elastic Agents 中配置 Beats 来采集定制日志
  10. 02-07GRE真题及答案解析整理