0%

关于Kotlin中的suspend关键字

Kotlin中的协程本质上来说就是个“线程框架”,这篇文章就来聊聊协程中著名的【挂起】,也就是suspend关键字

【挂起】的是什么

这个【挂起】操作其实挂起的是协程。来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
launch(Dispatchers.Main) {
...
val image = suspendingGetImage(imageId)
ivCover.setImageBitmap(image)
}

suspend fun suspendingGetImage(imageId : String) {
withContext(Dispatchers.IO){
getImage(imageId)
}
}

launch中的代码就是在协程中执行的,创建协程的函数除了launch()以外还有一个叫做async()的。言归正传,当launch()中执行到某一个suspend函数的时候,这个协程就会从当前线程挂起,通俗点说,就是这个协程从正在执行它的线程上脱离了。所以此时,线程和协程将会“兵分两路”,线程继续执行它的任务,而协程也将在挂起函数开始往下在挂起函数指定的线程中继续执行。

在挂起函数执行完成后,协程将为我们自动把线程切回来。因为你在挂起函数中(对应例子中的suspendingGetImage函数)指定线程时的参数不是Threads而是Dispatchers(调度器),当然你也可以设置特殊的Dispatchers让挂起函数不切回来。

所以挂起的定位就是:暂时切走,稍后再切回来

如何调用

挂起函数只能在协程中或者另外一个挂起函数中被调用

协程挂起之后是需要【恢复】的,也就是把线程切回原线程。而【恢复】这个功能是属于协程的,如果挂起函数没在协程里面被调用,那么【恢复】功能就没法实现。所以现在的逻辑图就是:

逻辑图

注意:suspend这个关键字并不起到把任何的协程挂起(切线程)的作用。若要自己实现挂起函数,那么你需要直接或间接调用某一个自带的挂起函数,只用一个suspend关键字是不行的!

既然这个suspend关键字并不能实现挂起,那么它是用来干嘛的呢?

suspend关键字的作用

提醒suspend关键字其实是一个函数的创建者对函数的调用者的提醒:(我是一个耗时函数,请在协程中调用我哦)

所以这个提醒会让我们的主线程不卡。原理就是,它将耗时任务需要切线程这个工作交给了函数的创建者而不是调用者,对于调用者来说事情将变得非常简单,调用者只会收到一个提醒:你需要把我放在协程里面

那么我可不可以在函数前面使用suspend关键字,但是我又不在函数内部调用别的挂起函数呢?我想说:可以,但没必要!因为你的这个挂起是没有意义的。

如何自定义挂起函数

什么时候自定义?

如果你的某个函数比较耗时,这个时候你就把他写成挂起函数。一般来说,有两类操作比较耗时:I/O操作计算操作,比如文件读写、网络交互、图片的模糊或美化处理…

再说一个特殊情况,就是这件事本身做起来并不慢,但是它需要等待。比如5s后再做这个操作

怎么写?

非常简单,函数前面加上suspend关键字,然后用withContext()把函数的内容包裹起来就可以了

最后

通过以上介绍就可以知道,其实挂起问题其实非常简单,只要你掌握了足够的前置知识,那么这些东西理解起来就非常简单!

您的支持将鼓励我的创作!

欢迎关注我的其它发布渠道