Take a look,從delay()方法看協程的掛起與恢復
highlight: vs theme: smartblue
攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第4天,點擊查看活動詳情
本篇文章主要是講解協程相關的知識點,並以
delay()
方法簡單分析協程如何實現的掛起以及恢復
協程實現的原理就是CPS+狀態機
,掘金很多優秀的文章都都寫的很好,我也寫不出太過於原理性的文章。本篇文章以一個掛起函數delay()
舉例,來簡單講解協程如何實現的掛起與恢復,以及為什麼delay()
不會阻塞主線程。
delay()
的掛起與恢復
我們以下面的代碼舉例:
kotlin
lifecycleScope.launch {
delay(1000)
val a = 10
val b = 50
println(a + b)
}
kotlin編譯器會將上面的代碼翻譯下面代碼(非常簡陋的偽代碼):
```kotlin
private fun test(completion: Continuation
val machine = completion as? StateMachine ?: StateMachine(completion)
when (machine.tag) {
0 -> {
//1.
//當delay方法執行完畢,就會調用machine的resumeWith()方法恢復協程執行
machine.tag = 1
delay(1000, machine)
}
1 -> {
//2.
val a = 10
val b = 50
println(a + b)
}
}
} ```
掛起
創建一個狀態機對象StateMachine
,第一次狀態機tag等於0,就會執行協程的掛起方法delay
,並傳入狀態機實例machine
,當delay
方法執行完畢後,就會調用傳入的machine
的resumeWith
方法恢復之後代碼的執行。
delay
方法是如何執行的呢?為什麼不會阻塞主線程?我們探究其實現原理:
kotlin
public suspend fun delay(timeMillis: Long) {
return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)
}
}
繼續看下HandlerContext
中scheduleResumeAfterDelay
方法(這裏以HandlerContext
類舉例):
kotlin
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
val block = Runnable {
with(continuation) { resumeUndispatched(Unit) }
}
handler.postDelayed(block, timeMillis.coerceAtMost(MAX_DELAY))
}
可以看到,這就是藉助了Handler
發送了一個延時執行的Message
消息,所以調用delay()
方法自然不會阻塞主線程
的執行了。
恢復
重點scheduleResumeAfterDelay
這段代碼:
kotlin
val block = Runnable {
with(continuation) { resumeUndispatched(Unit) }
}
當上面的Message
被執行後,就會調用傳入的continuation恢復協程的執行
,可以把這個continuation
理解為我們上面創建的machine
對象,調用的方法resumeUndispatched
是為resumeWith()
方法。
當協程的掛起方法delay
執行完畢後,就會走到狀態機StateMachine
的方法resumeWith
中,此時的tag已經變為1
了,所以當再次調用test(Continuation)
方法,並且走when
的第二個分支,執行下面的代碼塊邏輯:
1 -> {
//2.
val a = 10
val b = 50
println(a + b)
}
`
筆者這裏主要是簡單的描述了下
協程的掛起與恢復
,偽代碼寫的也非常簡陋,主要是方便大家理解,真實的情況請大家參考協程官方的源碼,有什麼疑問可以評論區一起交流。
總結
本篇文章主要是以delay()
方法作為一個入口,看下協程如何掛起與恢復的,並沒有多麼神祕,接下來準備繼續寫一系列協程相關的文章,如果您感覺文章寫的還行,可以給個贊支持下,感謝!!
參考文章
這是我看過的講解協程的最好的一篇文章,大概有幾萬字,我看了大概5-6個小時,非常值得大家細細品讀。
- kotlin密封sealed class/interface的迭代之旅
- 2022年12月12日—2022年12月25日Android精品文章一覽
- Sqlite簡易性能優化方案,給你的應用插上“翅膀”
- 築基篇:設置界面的開發利器Preference Library,瞭解一下~
- Android消息機制完整的執行流程,瞭解一下
- 你可能需要了解下的Android開發技巧(二)
- 超有用的Android開發技巧:攔截界面View創建
- Handler創建的幾個必備知識點,瞭解一下
- Android消息機制中Message常用的幾種監控方式
- 數見不鮮的RecyclerView使用技巧,你瞭解嗎(一)?
- 常用到的幾個Kotlin開發技巧,減少對業務層代碼的入侵
- 超好用的官方core-ktx庫,瞭解一下(終)~
- Take a look,從delay()方法看協程的掛起與恢復
- 超好用的官方core-ktx庫,瞭解一下~
- 官方core-ktx庫能對SparseArray系列、Pair開發帶來哪些便利?
- 官方core-ktx庫能對富文本Span開發帶來哪些便利2
- 你需要了解的官方core-ktx庫能對開發帶來哪些便利1
- LeakCanary如何監聽Fragment、Fragment View、ViewModel銷燬時機?
- 非反射動態設置TabLayout指示器的寬度
- 探究EventBus粘性事件實現機制