这个suspend关键字,并不是真正实现挂起,它其实是一个提醒。
先随便写一个自定义的 suspend 函数:
1 | suspend fun suspendingPrint() { |
输出的结果还是在主线程。
为什么没切换线程?因为它不知道往哪切,需要我们告诉它。
对比之前例子中 suspendingGetImage 函数代码:
1 | suspend fun suspendingGetImage(id: String) = withContext(Dispatchers.IO) { |
我们可以发现不同之处其实在于 withContext 函数。
其实通过 withContext 源码可以知道,它本身就是一个挂起函数,它接收一个 Dispatcher 参数,依赖这个 Dispatcher 参数的指示,你的协程被挂起,然后切到别的线程。
所以这个 suspend,其实并不是起到把任何把协程挂起,或者说切换线程的作用。
真正挂起协程这件事,是 Kotlin 的协程框架帮我们做的。
所以我们想要自己写一个挂起函数,仅仅只加上 suspend 关键字是不行的,还需要函数内部直接或间接地调用到 Kotlin 协程框架自带的 suspend 函数才行。
suspend 的意义?
这个suspend关键字,并不是真正实现挂起,它其实是一个提醒。
函数的创建者对函数的使用者的提醒:我是一个耗时函数,我被我的创建者用挂起的方式放在后台运行,所以请在协程里调用我。为什么 suspend 关键字并没有实际去操作挂起,但 Kotlin 却把它提供出来?因为它本来就不是用来操作挂起的。挂起的操作 —— 也就是切线程,依赖的是挂起函数里面的实际代码,而不是这个关键字。
所以这个关键字,只是一个提醒。。
如果你创建一个 suspend 函数但它内部不包含真正的挂起逻辑,编译器会给你一个提醒:redundant suspend modifier,告诉你这个 suspend 是多余的。
因为你这个函数实质上并没有发生挂起,那你这个 suspend 关键字只有一个效果:就是限制这个函数只能在协程里被调用,如果在非协程的代码中调用,就会编译不通过。
所以,创建一个 suspend 函数,为了让它包含真正挂起的逻辑,要在它内部直接或间接调用 Kotlin 自带的 suspend 函数,你的这个 suspend 才是有意义的。