Scope和Context
CoroutineScope
Scope指的是範圍,Coroutine作用的範圍,主要用來控制一群Coroutine的生命週期。 白話一點的描述來說,Scope比較像是一個容器,定義容器內的基本行為,從這個Scope產生出來的Coroutine都會繼承這個基本行為。
透過Scope產生Coroutine
重要概念:產生Coroutine不一定要透過Scope,Scope是一個容器來做到Structured Concurrency,可參考 Suspend修飾 簡單創建一個Coroutine。
在產生Coroutine之前,要先產生一個Scope,CoroutineScope它是一個介面,有一個參數CoroutineContext,在後面會說明它用途,現在只要知道一個Scope會包含一個Context來連結Coroutines的關係。
在Library的實作
自己的實作
不管用哪種方式,CoroutineContext都必須被指定。那如果不想指定CoroutineContext的行為怎麼辦?介面也不能是null。使用EmptyCoroutineContext代替,它是一個object class,所以不管產生幾個都是同一個實體。但建議別這麼做,因為創造了一個不能管理生命週期的Scope是沒有意義的。除非是Application等級的生命週期,當Application被殺掉,理所當然處理Coroutine的Thread正常也會消失,不用特別指定行為。
CoroutineContext
CoroutineContext是用來定義一個Coroutine的行為的一組元素。 他的實作元素有下面幾個:
Job:控管Coroutine生命週期。
CoroutineDispatcher:把工作分配在合適的Thread上。
CoroutineName:幫Coroutine命名,在Debug時很好用。
CoroutineExceptionHandler:處理未抓取的例外,就像是Thread.UncaughtExceptionHandler。
上面說它是一組元素是因為它是可以被組合起來的
產生一個新的Coroutine
為了快速使用Coroutine,我們使用runBlocking來launch或async產生一個Coroutine,因為runBlocking會阻塞目前的Thread,所以在實際產品Code千萬不要使用。
在launch後會回傳新的Coroutine,型別是Job,透過join()使目前的Coroutine suspend。
async會回傳一個Deferred代表之後再回來取值,透過await()可以把結果取回來,並使目前的Deferred suspend。
launch和async使用時機?
launch:只想啟動一個Task,不管結果如何。
async:啟動一個Task,但在特定的位置想知道結果是什麼。
CoroutineContext繼承關係
一個Coroutine通常會有一個Parent的Scope或是Parent的Coroutine。
Parent的Context = 預設 + 繼承的CoroutineContext + 參數
預設:CoroutineDispatcher -> Dispatcher.Default,CoroutineName -> "coroutine"。
繼承的CoroutineContext:從CoroutineScope或一個Coroutine產生。
參數:透過Coroutine建構式傳遞產生,如果有同樣的CoroutineContext元素,優先權會蓋過相同的元素。
Note:CoroutineContext可以透過+(加號)來進行結合成一組元素。覆蓋規則:加號的右邊會蓋過左邊,例如:(Dispatcher.Main + "Name") + (Dispatcher.IO) = (Dispatcher.IO + "Name")。
Child Coroutine的Context
透過Parent產生的Coroutine Context規則如下:
新的Coroutine Context = Parent Context + Job()
從父類別產生的Coroutine實體的Context,總是跟Parent的Context不一樣,會得到一個新的Job。
Last updated