本质
- 协程就是切线程。
- 协程其实就是一个线程框架,只不过比线程框架更方便一点。
写法
- 写一个
launch()函数,函数体里写上代码,就能切线程。 - 这个
launch()函数的含义:创建一个新协程,并在指定线程上运行它。 - 函数体内的代码就是新协程。
- 还有一个创建协程的函数,
async()
何时用
当需要切线程或指定线程的时候,比如想在后台更新任务,想在前台更新界面。
如何指定线程
使用withContext()函数,这个函数可以指定线程来运行代码,并且能在代码运行完后自动把线程切回来执行。
withContext()函数是挂起函数。
↓
这样可以让多线程之间进行协作,这就是「协程」(协作式的例程)。
suspend挂起
挂起:暂时切走,稍后再切回来。
launch()函数在执行到某个suspend函数时,这个协程会从当前线程中被挂起,也就是说脱离当前执行它的线程上脱离。- 注意,这时协程没有停止运行,只是这个协程所在的线程不再运行协程,协程和线程兵分两路。
实例:
启动一个执行在主线程的协程,实质上是往主线程post了一个任务,这个任务就是协程代码部分:
当协程遇到suspendingGetImage这个函数后被挂起,实质上是post任务提前结束。
此时主线程回去继续刷新界面。
此时协程在挂起函数指定的线程中继续运行。在这个例子中就是在withContext()函数所指定的IO线程。
挂起函数执行完成后,协程会再post一个任务,让剩余代码回到MAIN线程继续执行。其中起作用的就是Dispatchers调度器。(也可以自定义Dispatchers使之不切回主线程继续执行)
- 切回:
resume恢复。 - “挂起”的不是函数也不是线程,而是协程。
- 挂起函数只能在协程/另一个挂起函数中调用。
- “挂起”的操作靠的是挂起函数中的实际代码,而非
suspend关键字。上面的例子中,“挂起”动作发生在withContext()被调用时,而不是外部的suspend标记的函数。 suspend的作用:提醒调用者这是一个耗时函数,需要放进协程中使用。如果在主线程中调用了一个耗时函数,就会卡一下。所以要让耗时函数都放入后台中执行在,这样就不卡了。
如何自定义suspend函数
何时自定义
- 原则:如果某个函数很耗时,就写成挂起函数。一般是I/O操作 和 计算工作。比如文件读写、网络交互、图像处理等。
- 特殊情况:操作本身不慢,但需要等待一定时间后再进行的操作。
写法
给函数定义前加上suspend关键字即可。
非阻塞式挂起
非阻塞式:不卡线程
Java的Thread的挂起也是非阻塞式挂起。