而对于kotlin中协程最重要的一点特点是,是可以用同步的方式写出异步的代码

  1. coroutineScope.launch(Dispatchers.Main) { // 开始协程:主线程
  2. val token = api.getToken() // 网络请求:IO 线程
  3. val user = api.getUser(token) // 网络请求:IO 线程
  4. nameTv.text = user.name // 更新 UI:主线程
  5. }

启动一个协程可以使用 launch 或者 async 函数,协程其实就是这两个函数中闭包的代码块
当线程执行到协程的 suspend 函数的时候,暂时不继续执行协程代码了。

run code ..
// 主线程中
GlobalScope.launch(Dispatchers.Main) {
  val image = suspendingGetImage(imageId)  // 获取图片
  avatarIv.setImageBitmap(image)           // 显示出来
}

suspend fun suspendingGetImage(id: String) = withContext(Dispatchers.IO) {
  ...
}

当线程执行到“suspend 函数”时,它实质上会往你的主线程 post 一个 Runnable,这个 Runnable 就是你的协程代码:

handler.post {
  val image = suspendingGetImage(imageId)
  avatarIv.setImageBitmap(image)
}

然后线程就被掐断了,
我们的协程,它从 suspend 函数开始脱离启动它的线程,继续执行在 Dispatchers 所指定的 IO 线程。
紧接着在 suspend 函数执行完成之后,协程为我们做的最爽的事就来了:会自动帮我们把线程再切回来

切回来这个功能是协程的,如果你不在协程里面调用,恢复这个功能没法实现,所以也就回答了这个问题:为什么挂起函数必须在协程或者另一个挂起函数里被调用。

  • 协程是什么

协程就是切线程;

  • 挂起是什么

挂起就是可以自动切回来的切线程;

  • 挂起的非阻塞式

挂起的非阻塞式指的是它能用看起来阻塞的代码写出非阻塞的操作。

suspend

suspend中文意思是「暂停」或者「可挂起」
在之前我们讲到的协程的挂起,而挂起就是通过suspend来实现的

对于自定义挂起函数,需要在该函数内部直接/间接调用到某一个自带的挂起函数才行
【例如withContext()】

suspend fun getImage(imageId: Int) = withContext(Dispatchers.IO) {
    ...
}

suspend关键字到底什么作用

作用是:[提醒]
函数的创建者对函数的调用者的提醒
“我”是一个耗时的函数,我被我的创建者用挂起的方式放到了后台运行,所以要在协程里调用“我”。

https://www.jianshu.com/p/9857dec8561c