Kotlin Suspend挂起函数的使用详解

目录
  • 总结
  • 本质
  • 何时使用
  • 消除回调
  • 一些例子

总结

挂起(suspend)函数是所有协程的核心。 挂起函数可以执行长时间运行的操作并等待它完成而不会阻塞主线程。

挂起函数的语法与常规函数的语法类似,不同之处在于添加了suspend关键字。 它可以接受一个参数并有一个返回类型。 但是,挂起函数只能由另一个挂起函数或在协程内调用。

suspend fun backgroundTask(param: Int): Int {
     // long running operation
}

在背后,编译器将挂起函数转换为另一个没有挂起关键字的函数,该函数接受一个类型为 Continuation<T> 的附加参数。 例如,上面的函数将由编译器转换为:

fun backgroundTask(param: Int, callback: Continuation<Int>): Int {
   // long running operation
}

本质

  • 挂起函数只能在协程或者其他挂起函数中调用。
  • 挂起的对象是协程:launch ,async 或者其他函数创建的协程,在执行到某一个 suspend 函数的时候,这个协程会被挂起,即,从正在执行它的线程上脱离。就是说,当前线程跳过这个挂起函数,继续往下运行,但另一方面,线程的代码在到达 suspend 函数的时候被掐断,接下来协程会从这个 suspend 函数开始继续往下执行,不过是在指定的线程,执行完后,返回到之前挂起它的线程;
  • 简单来讲,在 Kotlin 中所谓的挂起,就是一个稍后会被自动切回来的线程调度操作;
  • 挂起函数的特点是使用同步的方式完成异步任务。
  • withContext 的作用就是指定切换的线程,比如:suspend fun suspendingGetImage(id: String) = withContext(Dispatchers.IO)

何时使用

如果你的某个函数比较耗时,也就是要等的操作,那就把它写成 suspend 函数。这就是原则。

耗时操作一般分为两类:I/O 操作和 CPU 计算工作。比如文件的读写、网络交互、图片的模糊处理,都是耗时的,通通可以把它们写进 suspend 函数里。

另外这个「耗时」还有一种特殊情况,就是这件事本身做起来并不慢,但它需要等待,比如 5 秒钟之后再做这个操作。这种也是 suspend 函数的应用场景。

消除回调

假设 postItem 由三个有依赖关系的异步子任务组成: requestTokencreatePostprocessPost,这三个函数都是基于回调的 API:

// 三个基于回调的 API
fun requestToken(block: (String) -> Unit)
fun createPost(
  token: String,
  item: Item,
  block: (Post) -> Unit)
)
fun processPost(post: Post)
fun postItem(item: Item) {
  requestToken { token ->
    createPost(token, item) { post ->
      processPost(post)
    }
  }
}

可以看到基于回调的 API 很容易造成大量缩进。如果代码中再加上一些条件、循环的逻辑,那么代码可读性会大大降低。Kotlin 的 suspend 关键字可以帮助我们消除回调,用同步的写法写异步:

suspend fun requestToken(): String
suspend fun createPost(token: String, item: Item): Post
suspend fun processPost(post)
suspend fun postItem(item: Item) {
  val token =                         
(0)

相关推荐

  • Kotlin 挂起函数CPS转换原理解析

    目录 正文 1.什么是CPS转换 2.CPS的过程是怎么让参数改变的 3.CPS的过程是怎么让返回值改变的 4.挂起函数的反编译 5.非挂起函数的分析 正文 普通函数加上suspend之后就成为了一个挂起函数,Kotlin编译器会将这个挂起函数转换成了带有参数Continuation<T>的一个普通函数,Continuation是一个接口,它跟Java中的Callback有着一样的功能,这个转换过程被称为CPS转换. 1.什么是CPS转换 挂起函数中的CPS转换就是把挂起函数转换成一个带有Ca

  • Kotlin挂起函数原理示例剖析

    目录 一.序言 二.CPS原理 CPS参数变化 CPS返回值变化 三.挂起函数的反编译 四.伪挂起函数 五.多个挂起函数前后关联 六.在Java中调用suspend函数 七.总结 一.序言 Kotlin挂起函数平时在学习和工作中用的比较多,掌握其原理还是很有必要的.本文将一步一步带着大家分析其原理实现. ps: 文中所用的Kotlin版本是1.7.0. 二.CPS原理 在某个Kotlin函数的前面加个suspend函数,它就成了挂起函数(虽然内部不一定会挂起,内部不挂起的称为伪挂起函数). 先随

  • Kotlin挂起函数的详细介绍

    Kotlin 协程的优势: 解决回调地狱的问题. 以同步的方式完成异步任务. 示例: fun main() { runBlocking { val a = getA() println(a) val b = getB(a) println(b) val c = getC(b) println(c) } } suspend fun getA(): String { withContext(Dispatchers.IO) { delay(2000L) } return "A content"

  • Kotlin Suspend挂起函数的使用详解

    目录 总结 本质 何时使用 消除回调 一些例子 总结 挂起(suspend)函数是所有协程的核心. 挂起函数可以执行长时间运行的操作并等待它完成而不会阻塞主线程. 挂起函数的语法与常规函数的语法类似,不同之处在于添加了suspend关键字. 它可以接受一个参数并有一个返回类型. 但是,挂起函数只能由另一个挂起函数或在协程内调用. suspend fun backgroundTask(param: Int): Int { // long running operation } 在背后,编译器将挂起

  • Kotlin 嵌套函数开发技巧详解

    目录 1.嵌套函数 2.@JvmOverloads快捷实现函数重载 3.延迟初始化lateinit var 4.@JvmField减少属性set和get方法的生成 1.嵌套函数 业务开发中,我们可能会遇到这样一个场景:一个函数只会被某一处多次调用,且不想让这个函数在该类的其他地方调用,这个时候就需要对这个函数的访问性进行进一步限制. private是无法满足的,这个时候我们就可以使用嵌套函数提供更好的封装: fun test1() { //被限制访问行的函数 fun test2(content:

  • Kotlin协程launch启动流程原理详解

    目录 1.launch启动流程 反编译后的Java代码 2.协程是如何被启动的 1.launch启动流程 已知协程的启动方式之一是Globalscope.launch,那么Globalscope.launch的流程是怎样的呢,直接进入launch的源码开始看起. fun main() { coroutineTest() Thread.sleep(2000L) } val block = suspend { println("Hello") delay(1000L) println(&q

  • Kotlin 语言中调用 JavaScript 方法实例详解

    Kotlin 语言中调用 JavaScript 方法实例详解 Kotlin 已被设计为能够与 Java 平台轻松互操作.它将 Java 类视为 Kotlin 类,并且 Java 也将 Kotlin 类视为 Java 类.但是,JavaScript 是一种动态类型语言,这意味着它不会在编译期检查类型.你可以通过动态类型在 Kotlin 中自由地与 JavaScript 交流,但是如果你想要 Kotlin 类型系统的全部威力 ,你可以为 JavaScript 库创建 Kotlin 头文件. 内联 J

  • kotlin 官方学习教程之基础语法详解

    kotlin 官方学习教程之基础语法详解 Google 在今天的举行了 I/O 大会,大会主要主要展示内有容 Android O(Android 8.0)系统.Google Assistant 语音助手.Google 智能音箱.人工智能.机器学习.虚拟现实等.作为一个 Android 开发者,我关心的当然是 Android O(Android 8.0)系统了,那么关于 Android O 系统的一个重要消息是全面支持 Kotlin 编程语言,使得 Kotlin 成为了 Android 开发的官方

  • Kotlin startActivity跳转Activity实现流程详解

    目录 带参数的调整 自定义数据传输 startActivityForResult 小结 从一个Activity跳到另一个Activity 在编写安卓代码是最常见的事情了.我们不可能在一个页面中,把所有的事情都做完. 在kotlin中跳转的程序也比较简单,跟java差不多.如果熟悉java代码的话,只需要把代码改变过来而已. 带参数的调整 从一个Activity跳到另一个Activity 中,如同调用函数一样,可以把数据传递给另外的Activity中,Activity在接受到这个数据后,可以根据数

  • 基于C++ bitset常用函数及运算符(详解)

    C++ bitset--高端压位卡常题必备STL ------------------------------------------------------------ 以下内容翻译自cplusplus.com,极大地锻炼了我的英语能力. bitset存储二进制数位. bitset就像一个bool类型的数组一样,但是有空间优化--bitset中的一个元素一般只占1 bit,相当于一个char元素所占空间的八分之一. bitset中的每个元素都能单独被访问,例如对于一个叫做foo的bitset,

  • C++ 中const对象与const成员函数的实例详解

    C++ 中const对象与const成员函数的实例详解 const对象只能调用const成员函数: #include<iostream> using namespace std; class A { public: void fun()const { cout<<"const 成员函数!"<<endl; } void fun() { cout<<"非const成员函数 !"<<endl; } }; int

  • web开发之对比时间大小的工具函数的实例详解

    web开发之对比时间大小的工具函数的实例详解 js时间大小比较,格式yyyy-MM-dd hh:mm:ss 把时间比较封装成一个工具函数: /** * 比较两个时间的大小 * 时间格式:yyyy-MM-dd hh:mm:ss * @param {Object} beginTime 开始时间 * @param {Object} endTime 结束时间 */ var getDataLarge = function(beginTimeString,endTimeString){ var b = be

  • Oracle中的INSTR,NVL和SUBSTR函数的用法详解

    Oracle中INSTR的用法: INSTR方法的格式为 INSTR(源字符串, 要查找的字符串, 从第几个字符开始, 要找到第几个匹配的序号) 返回找到的位置,如果找不到则返回0. 例如:INSTR('CORPORATE FLOOR','OR', 3, 2)中,源字符串为'CORPORATE FLOOR', 在字符串中查找'OR',从第三个字符位置开始查找"OR",取第三个字后第2个匹配项的位置. 默认查找顺序为从左到右.当起始位置为负数的时候,从右边开始查找. 所以SELECT I

随机推荐