一、協(xié)程概念
協(xié)程是一種并發(fā)設(shè)計模式,用它來簡化異步執(zhí)行的代碼。
優(yōu)點:
- 輕量:協(xié)程可以掛起,比阻塞更省內(nèi)存
- 減少內(nèi)存泄漏
- 支持取消
- 支持Jatpack集成
二、CoroutineScope 協(xié)程作用域
- GlobalScope 全局的,一般不會釋放,所以基本不要
- MainScope 需要自己 取消
- LifecycleScope 不需要關(guān)心取消,自動綁定Lifecycle生命周期了
- ViewModelScope 不需要關(guān)心取消,自動綁定ViewModel生命周期了
三、CoroutineScope.launch、CoroutineScope.async
不阻塞線程,在后臺開啟協(xié)程,默認(rèn)立馬執(zhí)行- 區(qū)別:launch 返回是Job,async 返回是Deferred<T> ,可以調(diào)用await()等待獲取結(jié)果
四、suspend(掛起) 函數(shù)特點
suspend函數(shù),不阻塞線程必須在協(xié)程或者suspend函數(shù)里面執(zhí)行要等suspend函數(shù)執(zhí)行完成,代碼才繼續(xù)往下執(zhí)行
五、suspend withContext 、suspend coroutineScope
- 屬于suspend 函數(shù),不阻塞線程
里面最后一行作為返回值,要等里面的代碼執(zhí)行完成,才繼續(xù)往下執(zhí)行- 區(qū)別:withContext可以設(shè)置作用域,coroutineScope不行
六、CoroutineStart - 啟動模式
- CoroutineStart.DEFAULT: 協(xié)程創(chuàng)建后,立即開始調(diào)度,但 有可能在執(zhí)行前被取消。在調(diào)度前如果協(xié)程被取消,其將直接進入取消響應(yīng)的狀態(tài)。
- CoroutineStart.ATOMIC : 協(xié)程創(chuàng)建后,立即開始調(diào)度, 協(xié)程執(zhí)行到第一個掛起點之前不響應(yīng)取消。其將調(diào)度和執(zhí)行兩個步驟合二為一,就像它的名字一樣,其保證調(diào)度和執(zhí)行是原子操作,因此協(xié)程也 一定會執(zhí)行。
- CoroutineStart.LAZY : 只要協(xié)程被需要時(主動調(diào)用該協(xié)程的 start、 join、 await等函數(shù)時 ),才會開始調(diào)度,如果調(diào)度前就被取消,協(xié)程將直接進入異常結(jié)束狀態(tài)。
- CoroutineStart.UNDISPATCHED : 協(xié)程創(chuàng)建后,立即在當(dāng)前線程中執(zhí)行,直到遇到第一個真正掛起的點。 是立即執(zhí)行,因此協(xié)程 一定會執(zhí)行
六、Dispatchers - 協(xié)程調(diào)度器
- Default: 默認(rèn)調(diào)度器 ,適合處理后臺計算,其是一個 CPU 密集型任務(wù)調(diào)度器
- IO: IO 調(diào)度器,適合執(zhí)行 IO 相關(guān)操作,其是 IO 密集型任務(wù)調(diào)度器
- Main: UI 調(diào)度器,根據(jù)平臺不同會被初始化為對應(yīng)的 UI 線程的調(diào)度器, 例如在Android 平臺上它會將協(xié)程調(diào)度到 UI 事件循環(huán)中執(zhí)行,即通常在 主線程上執(zhí)行。
- Unconfined:“無所謂“調(diào)度器,不要求協(xié)程執(zhí)行在特定線程上。協(xié)程的調(diào)度器如果是 Unconfined, 那么它在掛起點恢復(fù)執(zhí)行時會在恢復(fù)所在的線程上直接執(zhí)行,當(dāng)然, 如果嵌套創(chuàng)建以它為調(diào)度器的協(xié)程,那么這些協(xié)程會在啟動時被調(diào)度到協(xié)程框架內(nèi)部的事件循環(huán)上,以避免出現(xiàn) StackOverflow。
七、協(xié)程使用
// 協(xié)程測試類
object CoroutineTest : CoroutineScope by MainScope() { // 代理類實現(xiàn) 協(xié)程作用域
// 協(xié)程測試
suspend fun coroutineTest() {
// 掛起函數(shù),要等代碼執(zhí)行完,才往下執(zhí)行
val job = launch(Dispatchers.IO, CoroutineStart.LAZY) {
// GlobalScope 頂級作用域 其它作用域取消,對其沒有影響
GlobalScope.launch {
// ...
delay(1000)
}
val deferred = async(Dispatchers.IO) {
"async result"
}
// withContext 掛起方法要在 協(xié)程 或者 suspend方法 里面調(diào)用
val withContextRes = withContext(Dispatchers.Default) {
// ...
"withContext result"
}
// await 掛起方法 要在 協(xié)程 或者 suspend方法 里面調(diào)用
val asyncRes = deferred.await() // 掛起 獲取結(jié)果
}
// CoroutineStart.LAZY 要調(diào)用 start 或者 await()方法后才執(zhí)行
job.start()
// 取消并等待執(zhí)行完成
job.cancelAndJoin()
}
}