簡單來說,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
}
}
}
}
可以很明顯的看到編譯器的提示在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僅僅就是在作用域内為協程進行線程切換的快捷方式。