Kotlin 協(xié)程 supervisorScope {} 運(yùn)行崩潰解決方法
Kotlin 協(xié)程 supervisorScope {} 運(yùn)行崩潰解決
前言
簡(jiǎn)單介紹supervisorScope函數(shù),它用于創(chuàng)建一個(gè)使用了 SupervisorJob 的 coroutineScope,
該作用域的特點(diǎn):拋出的異常,不會(huì) 連鎖取消 同級(jí)協(xié)程和父協(xié)程。
看過(guò)很多 supervisorScope {} 文檔的使用,我照抄一摸一樣的代碼,運(yùn)行就崩潰,最后找到了解決方法,應(yīng)該是kotlin版本更新做過(guò)改動(dòng),當(dāng)前我使用的是 androidx.core:core-ktx:1.9.0
解決方法
需要將CoroutineExceptionHandler,作為參數(shù),才有效果,不然會(huì)崩潰。
private fun test() { // 原來(lái)的寫法,現(xiàn)在會(huì)崩潰 // runBlocking { // Log.d("TAG", "Start") // launch { // delay(100) // Log.d("TAG", "Task from runBlocking") // } // supervisorScope { // val firstChild = launch { // Log.d("TAG", "First Child") // throw AssertionError("First child is cancelled") // } // val secondChild = launch { // Log.d("TAG", "Second Child") // } // Log.d("TAG", "Cancelling supervisor") // } // Log.d("TAG", "End") // } // 最新的寫法 runBlocking { Log.d("TAG", "Start") launch { delay(100) Log.d("TAG", "Task from runBlocking") } supervisorScope { // 需要將CoroutineExceptionHandler,作為參數(shù),才有效果,不然會(huì)崩潰 val firstChild = launch(CoroutineExceptionHandler { _, _ -> }) { Log.d("TAG", "First Child") throw AssertionError("First child is cancelled") } val secondChild = launch { Log.d("TAG", "Second Child") } Log.d("TAG", "Cancelling supervisor") } Log.d("TAG", "End") } }
補(bǔ)充:
kotlin 協(xié)程異常處理
import kotlinx.coroutines.* import java.net.URL suspend fun fetchResponse(code: Int, delay: Int) = coroutineScope { val deferred: Deferred<String?> = async { URL("http://httpstat.us/$code?sleep=$delay").readText() } try { val response = deferred.await() println(response) } catch(ex: CancellationException) { println("${ex.message} for fetchResponse $code") } } runBlocking { val handler = CoroutineExceptionHandler {_, ex -> println("exception handled: ${ex.message}") } val job = launch(Dispatchers.IO + SupervisorJob() + handler) { // 協(xié)程1 launch{fetchResponse(202, 1000)} // 協(xié)程2 launch{fetchResponse(404, 2000)} // 協(xié)程3 launch{fetchResponse(200, 3000)} // 協(xié)程4 } job.join() }
如上的運(yùn)行結(jié)果如下所示
202 Accepted
Parent job is Cancelling for fetchResponse 200
exception handled: http://httpstat.us/404?sleep=2000
分析:
一、fetchResponse使用的是coroutineScope來(lái)包起來(lái),那么如果有協(xié)程的異常則該函數(shù)不會(huì)自己處理會(huì)向上傳播;如果不想讓協(xié)程的異常向外傳播則可以使用supervisorScope
二、fetchResponse內(nèi)部函數(shù)使用的是async/await, 并且try/catch沒(méi)有將async包起來(lái),那么如果async發(fā)生了異常會(huì)發(fā)生什么事情呢?
1、async作為 根協(xié)程(CoroutineScope或者 supervisorScope的直接子協(xié)程),異常不會(huì)自動(dòng)拋出;它會(huì)在你調(diào)用await的時(shí)候才拋出所以這里的try/catch只是將await包起來(lái)即可
2、那么既然await的異常已經(jīng)被捕獲了,為何404還會(huì)向上拋出異常導(dǎo)致其他協(xié)程的取消呢?這是因?yàn)楫?dāng)async發(fā)生異常的時(shí)候會(huì)立即把異常拋出給父節(jié)點(diǎn),因?yàn)楦腹?jié)點(diǎn)是coroutineScope所以繼續(xù)向上拋出直到協(xié)程1,然后協(xié)程1將所有的子協(xié)程取消
那么問(wèn)題來(lái)了:1中說(shuō)的async不會(huì)拋出異常,2中又說(shuō)會(huì)立即拋出異常;那么是否是自相矛盾呢?
async拋出的異常try/catch是沒(méi)法捕獲的,它會(huì)向父協(xié)程傳播異常(即父子協(xié)程之間的異常傳播,而不是代碼級(jí)別的異常傳播所以try/catch捕獲不到;曾經(jīng)使用catch(ex: Exception) 嘗試捕獲確實(shí)沒(méi)有捕獲成功)
綜上所述,async跟await都是有拋出異常,只是他們拋出的方式不一樣,async是父子協(xié)程之間的異常傳播而await是代碼邏輯的異常傳播可被try/catch捕獲到
那么問(wèn)題來(lái)了:async不能被try/catch捕獲到,該怎樣捕獲呢?
這里的launch使用了CoroutineExceptionHandler進(jìn)行捕獲;當(dāng)異常傳到協(xié)程1的時(shí)候,繼續(xù)向上傳播;因?yàn)閰f(xié)程1的父協(xié)程是SupervisorJob(為何協(xié)程1的父協(xié)程是SupervisorJob可以見(jiàn)http://chabaoo.cn/program/2975787fp.htm)所以需要協(xié)程1自己處理;因?yàn)閰f(xié)程1的launch中包含了handler的異常捕獲則會(huì)使用該異常類進(jìn)行處理
這里launch可以使用CoroutineExceptionHandler進(jìn)行捕獲,那么async可以使用CoroutineExceptionHandler進(jìn)行捕獲么? 答案是不可以的,async對(duì)應(yīng)的await需要使用try/catch進(jìn)行捕獲
注意:coroutineScope構(gòu)建器中拋出的異常,或由協(xié)程創(chuàng)建的協(xié)程中拋出的異常,不會(huì)被 try/catch捕獲!
具體的可參考:http://chabaoo.cn/article/264218.htm
FQ版(英文版):https://medium.com/androiddevelopers/exceptions-in-coroutines-ce8da1ec060c
到此這篇關(guān)于Kotlin 協(xié)程 supervisorScope {} 運(yùn)行崩潰解決的文章就介紹到這了,更多相關(guān)Kotlin 協(xié)程 supervisorScope {} 運(yùn)行崩潰內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)自動(dòng)文本框提示功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)自動(dòng)文本框提示功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10android使用PullToRefresh實(shí)現(xiàn)下拉刷新和上拉加載
本篇文章主要介紹了android使用PullToRefresh實(shí)現(xiàn)下拉刷新和上拉加載,具有一定的參考價(jià)值,有興趣的可以了解一下。2016-12-12更新Android Studio 3.0碰到的問(wèn)題小結(jié)
本文是小編給大家分享的更新Android Studio 3.0碰到的問(wèn)題小結(jié),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-11-11Android?Studio實(shí)現(xiàn)簡(jiǎn)易計(jì)算器設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了Android?Studio實(shí)現(xiàn)簡(jiǎn)易計(jì)算器設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Android實(shí)現(xiàn)觸摸移動(dòng)的懸浮窗口功能
這篇文章主要介紹了Android實(shí)現(xiàn)觸摸移動(dòng)的懸浮窗口功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Android FTP服務(wù)器上傳文件攻略(代碼詳解)
這篇文章主要介紹了Android FTP服務(wù)器上傳文件攻略,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06解決Android Studio 格式化快捷鍵和QQ 鎖鍵盤快捷鍵沖突問(wèn)題
每次打開(kāi)qq使用android studio格式化的快捷鍵Ctrl + Alt +L時(shí),總是出現(xiàn)qq鎖鍵盤提示,怎么回事呢?下面小編給大家?guī)?lái)了android studio格式化的快捷鍵和qq快捷鍵之間的沖突的處理方法,需要的朋友參考下吧2017-12-12Android編程心得分享——JSON學(xué)習(xí)過(guò)程
在我們初步學(xué)習(xí)JSON時(shí)我們都知道JSON作為現(xiàn)在比較流行的數(shù)據(jù)交換格式,有著它的許多優(yōu)點(diǎn),這里將我學(xué)習(xí)JSON的過(guò)程記錄如下2013-06-06Android中Spinner控件之鍵值對(duì)用法實(shí)例分析
這篇文章主要介紹了Android中Spinner控件之鍵值對(duì)用法,實(shí)例分析了Spinner控件控件的鍵值對(duì)實(shí)用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09