天天看點

kotlin中CoroutineScope CoroutineContext的了解

簡單來說,CoroutineScope是啟動協程的作用域,所有協程都需要在作用域中啟動,并且作用域内部建立子協程則會自動傳播給子協程;

而CoroutineContext則是在協程作用域中執行的線程切換。

1、首先我們來看下Scope作用域的了解,示例代碼:

import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {
    runBlocking {
        val scope0 = this
        // scope0是頂級協程範圍。
        scope0.launch {
            val scope1 = this
            // scope1從scope0繼承其上下文。它用自己的作業替換Job字段,該作業是scope0中該作業的子級。
            // 它保留了Dispatcher字段,是以啟動的協程使用runBlocking建立的排程程式。
            scope1.launch {
                val scope2 = this
                // scope2繼承自scope1
            }
        }
    }
}
           
kotlin中CoroutineScope CoroutineContext的了解

可以很明顯的看到編譯器的提示在runBlocking、scope0、scope1、scope2中均是指的同一個作用域CoroutineScope。

是以這也就解釋了文章SupervisorJob使用的原因,如果裡面的scope1取消掉,或者scope2在使用過程中抛出異常,

那麼這整片的scope均會取消掉或者抛出異常影響到外層的scope執行,也即會影響到scope0、runblocking作用域的代碼執行。

這也就是kotlin作用域的自動傳播機制。

2、下面看下Context的了解,示例代碼:

runBlocking(Dispatchers.Main) {
        withContext(Dispatchers.IO) { }
        withContext(Dispatchers.Main) { }
        withContext(Dispatchers.IO) { }
        withContext(Dispatchers.Default) { }
    }
           

同樣是使用runblocking建立的協程作用域,不同的是這裡使用了帶context參數的方式,在這個runblocking作用域内使用Dispatchers進行了多次的context切換,也就是線程的多次切換,其實質就是context提供了對底層線程的引用,友善我們再作用域内部進行線程的切換

再來看下CoroutineScope的源碼,其實CoroutineScope内部含有CoroutineContext

public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
}
           

綜上,CoroutineScope是協程作用域,其内部本身就含有一個CoroutineContext線程,預設是主線程。在協程作用域内可以建立更多的子協程,這些協程内部是自動繼承自父協程的生命周期。而CoroutineContext僅僅就是在作用域内為協程進行線程切換的快捷方式。