08 Kotlin的协程

115 阅读3分钟

本质

  • 协程就是切线程。
  • 协程其实就是一个线程框架,只不过比线程框架更方便一点。

写法

  • 写一个launch()函数,函数体里写上代码,就能切线程。
  • 这个launch()函数的含义:创建一个新协程,并在指定线程上运行它。
  • 函数体内的代码就是新协程。

image.png

  • 还有一个创建协程的函数,async()

image.png

何时用

当需要切线程或指定线程的时候,比如想在后台更新任务,想在前台更新界面。

如何指定线程

使用withContext()函数,这个函数可以指定线程来运行代码,并且能在代码运行完后自动把线程切回来执行。 withContext()函数是挂起函数。

image.pngimage.png

这样可以让多线程之间进行协作,这就是「协程」(协作式的例程)。

suspend挂起

挂起:暂时切走,稍后再切回来。

  • launch()函数在执行到某个suspend函数时,这个协程会从当前线程中被挂起,也就是说脱离当前执行它的线程上脱离。
  • 注意,这时协程没有停止运行,只是这个协程所在的线程不再运行协程,协程和线程兵分两路。

实例:

启动一个执行在主线程的协程,实质上是往主线程post了一个任务,这个任务就是协程代码部分:

image.png

当协程遇到suspendingGetImage这个函数后被挂起,实质上是post任务提前结束。

此时主线程回去继续刷新界面。 此时协程在挂起函数指定的线程中继续运行。在这个例子中就是在withContext()函数所指定的IO线程。

image.png

挂起函数执行完成后,协程会再post一个任务,让剩余代码回到MAIN线程继续执行。其中起作用的就是Dispatchers调度器。(也可以自定义Dispatchers使之不切回主线程继续执行)

  • 切回:resume恢复。
  • “挂起”的不是函数也不是线程,而是协程。
  • 挂起函数只能在协程/另一个挂起函数中调用。
  • “挂起”的操作靠的是挂起函数中的实际代码,而非suspend关键字。上面的例子中,“挂起”动作发生在withContext()被调用时,而不是外部的suspend标记的函数。
  • suspend的作用:提醒调用者这是一个耗时函数,需要放进协程中使用。如果在主线程中调用了一个耗时函数,就会卡一下。所以要让耗时函数都放入后台中执行在,这样就不卡了。

如何自定义suspend函数

何时自定义

  • 原则:如果某个函数很耗时,就写成挂起函数。一般是I/O操作 和 计算工作。比如文件读写、网络交互、图像处理等。
  • 特殊情况:操作本身不慢,但需要等待一定时间后再进行的操作。

写法

给函数定义前加上suspend关键字即可。

image.png

非阻塞式挂起

非阻塞式:不卡线程

Java的Thread的挂起也是非阻塞式挂起。