關於Android LifecycleScope的一點點發現

語言: CN / TW / HK

例子

image-20220119150748335

程式碼的執行順序應該是one(),two()還是two(),one(),或者是兩個呼叫的時機是隨機的,看協程的排程呢?相信很多人都會選擇最後一個.但實際無論執行多少次都是下面的結果

image-20220119151317244

並且launch()方法傳入的suspend 函式甚至會阻塞主執行緒,怎麼回事兒,這個協程是假的協程?嗎!

先說結論

Kotlin的協程在不同的平臺有不同的實現方式.本文以我最熟悉的Android平臺為例.在Android中,啟動一個協程使用Dispatcher.Main.immediate作為排程器的話,如果當前執行緒是主執行緒,就會將任務立即在主執行緒執行,如果是在其它執行緒中,使用Handler.post()方法分給主執行緒去執行.

如果是Dispatcher.Main作為排程器,就會直接使用主執行緒的Handler.post()去執行.

CoroutineDispatcher:協程排程器

image-20220119110709671

image-20220119110813517

在匯入了androidx.lifecycle:lifecycle-runtime-ktx依賴後,可以在Activity中使用lifecycleScope.launch{}啟動一個協程,這裡預設的上下文就是 EmptyCoroutineContext,因此啟動的協程上下文就是

kotlin lifecycleScope.coroutineContext+EmptyCoroutineContext

看下lifecycleScope是怎麼來的

image-20220119145648128

這樣lifecycleScope.launch{}這樣啟動一個協程預設的排程器就是Dispatcher.Main.immediate

Dispatcher顧名思義就是排程器,在這裡就是負責協程的排程功能,匯入依賴檢視Android平臺的Disptcher.Main的最終實現是由HandlerContext實現的

image-20220119115307629

HandlerContext重寫了isDispatchNeeded方法

image-20220119115553319

檢視isDispatchNeeded的註釋可知道如果該方法返回true就會通過dispatch()將協程分發出去,false就會令協程在當前執行緒恢復,因此Disptcher.Main會始終呼叫dispather()來進行分發,而Dispatcher.Main.immediate只有在非主執行緒中會呼叫dispatch().何時會呼叫CoroutineDispatcher.isDispatchNeeded()方法呢?通過檢視函式呼叫在DispatchedContinuation.resumeWith()方法中使用到了它.

DispatchedContinuation:協程排程的發起者

這裡只關注DispatchedContinuation是如何讓協程立即在當前執行緒恢復的邏輯

image-20220119142039471

image-20220119143447268

executeUnconfined()方法是DispatchedContinuation的一個拓展函式,協程的執行是交給EventLoop處理,它類似Handler的MessageQueue,如果當前執行緒的佇列已滿就會使用EventLoop.dispatchUnconfined()將這個協程排程到當前的EventLoop中,否則直接呼叫runUnconfinedEventLoop()將協程執行