本篇將會介紹
1. CoroutineScope
2. Dispatchers
3. Job
4. Handle Exception
5. Exception Path
1. CoroutineScope
CoroutineScope 就是 Job 的執行範圍,舉個例子:
今天你打算刷完某個副本(遊戲),但是你使用電腦的時間是 19:00~22:00,時間到的時候,你發現還沒打完,這時只能取消這個念頭,關掉電腦.
Job:刷完某個副本
Scope:19:00~22:00
當 Job 執行的時間超出 Scope 時,將會被強制取消,這就是 CoroutineScope 的作用.
2. Dispatchers
負責把 Job 分派給執行緒,舉個例子:
今天公司的主管將 A 任務分給 A 員工, B 任務分給 B 員工.
Dispatchers : 主管
Job : 任務
3. Job
在 Coroutine 的世界裡,Job 就是任務,注意一點 Job 有 parent-child 的關係.舉個例子:
lifecycleScope.launch {
witchContext(Dispatchers.IO) {
..... }
}
在上述的程式碼中 launch
就是一個 Job,而 withContext
就是 launch
的 Child Job.
4. Handle Exception
Coroutine 處理 Exception 的機制非常依賴 Job,舉個例子:
val exceptionHandler = CoroutineExceptionHandler {
coroutineContext, throwable ->
Log.d("exp"," exceptionHandler")
}
lifecycleScope.launch(exceptionHandler) {
val defferResult = async {
throw Exception()
}
try {
val result = defferResult.await()
} catch (e: Exception) {
Log.d("exp"," try-catch")
}
}
async
是 launch
的 Child Job,當發生 Exception 的時候,Child Job 會將 Exception 傳遞給 Parent Job,導致 execeptionHandler 與 try-catch 都會有接到 Exception.
5. Exception Path
發生 Exception 時 Job 會將 Exception 傳遞給 Parent Job,那這個 Path 有幾個規則:
1. Child Job 會詢問 Parent Job :你是否可以處理這個 Exception
2. Parent Job 接收到 Exception 後會回應 Child Job:”是,我可以處理這個 Exception” 或者 “不,這個 Exception 你必須自己處理”.
3. 處理的方式會依據 Job 的不同而有不同的 Path
介紹 Job 對於 Exception 的處理方式:
launch
:會將 Exception 傳遞給 Parent Job,如果 Parent Job 無法處理 Exception,launch
將把 Exception 交給 ExceptionHandler 處理,如果沒有 ExceptionHandler 那麼這個 Exception 將會拋給thread.uncaughtexceptionhandler
處理.async
: 會將 Exception 傳遞給 Parent Job,如果 Parent Job 無法處理 Exception,async
什麼事都不會做;但是 “呼叫await
“ 時會將 Exception 重新拋出.withContext
:接受 Child Job 的 Exception,不會將 Exception 傳遞給 Parent Job,但會將 Exception 重新拋出.coroutineScope
:接受 Child Job 的 Exception,不會將 Exception 傳遞給 Parent Job,但會將 Exception 重新拋出.SupervisorJob
,supervisorScope
:不接受 Child Job 的 Exception,強制 Child Job 要自己處理 Exception;不會將 Exception 傳遞給 Parent Job,但會將 Exception 重新拋出.Job()
: 如果有 Parent Job 則 接受 Child Job 的 Exception 並交由 Parent Job 處理,如果沒有則 拒絕 Child Job 的 Exception,強制 Child Job 自行處理 Exception.
針對 withContext, coroutineScope, SupervisorJob, supervisorScope 做個比較
withContext, coroutineScope:由於 withContext
或 coroutineScope
會跟 launch
說 “我會處理 Exception”,接著會將 Exception 重新拋出,所以外面的 try-catch 才接得到 Exception.
lifecycleScope.launch {
try {
withContext {
launch {
throw Exception()
}
}
} catch (e: Exception){
Log.d("exp", " receive")
}
}
SupervisorJob:由於 launch
有設定 Parent Job 是 SupervisorJob,所以 SupervisorJob 會跟 launch
說 “我無法處理 Exception”,進而觸發 launch
的 Exception Handle 機制將 Exception 交給 exceptionHandler 處理.
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
Log.d("exp"," exceptionHandler")
}
lifecycleScope.launch {
launch(SupervisorJob() + exceptionHandler) {
throw Exception()
}
}
SupervisorScope:SupervisorScope 會跟launch
說“我無法處理 Exception”,進而觸發 launch
的 Exception Handle 機制將 Exception 交給 exceptionHandler 處理.
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
Log.d("exp"," exceptionHandler")
}
lifecycleScope.launch {
supervisorScope {
launch(exceptionHandler) {
throw Exception()
}
}
}