Android 是如何捕捉 java 異常的
一、 java 異常全局捕捉
用于 java 異常全局捕捉代碼:
val default = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { t, e -> // 處理異常 Log.e("Uncaught", "exception message : "+ e.message) // 將異常回執(zhí)給原注冊(cè)的 handler default.uncaughtException(t, e) }
以上是很簡(jiǎn)單的一段代碼,經(jīng)常被用于 java 異常全局捕捉,但我的疑問(wèn)是,他是怎么實(shí)現(xiàn)全局捕捉的,帶著這樣的疑問(wèn),我們來(lái)扒一下代碼看看。
順藤摸瓜,我們看看靜態(tài)方法 getDefaultUncaughtExceptionHandler
是被誰(shuí)調(diào)用的,看了下所有的類(lèi)調(diào)用的類(lèi),唯有 ThreadGroup
最靠譜:
在 parent
為空的情況下,就會(huì)調(diào)用 getDefaultUncaughtExceptionHandler
來(lái)回調(diào)異常,然后繼續(xù)順藤摸瓜,看看 ThreadGroup
的 uncaughtException
是被誰(shuí)觸發(fā)的,搜了一個(gè)圈,沒(méi)有一個(gè)靠譜的。在我躊躇時(shí),順帶瞄了一眼注釋?zhuān)?strong>奇跡發(fā)現(xiàn):
- Called by the Java Virtual Machine when a thread in this - thread group stops because of an uncaught exception, and the thread - does not have a specific {[@link ](/link%20)Thread.UncaughtExceptionHandler} - installed.
意思是:當(dāng)一個(gè)未捕獲的異常導(dǎo)致線(xiàn)程組中的線(xiàn)程停止時(shí),JVM 會(huì)調(diào)用該方法。那我們就去搜搜 jvm 的源碼,看看是怎么觸發(fā)這個(gè)方法的。
在 Hotspot
虛擬機(jī)源碼的 thread.cpp
中的 JavaThread::exit
方法發(fā)現(xiàn)了這樣的一段代碼,并且還給出了注釋?zhuān)?/p>
在線(xiàn)程調(diào)用 exit
退出時(shí),如果有未捕獲的異常,則會(huì)調(diào)用 Thread.dispatchUncaughtException
方法,然后我們繼續(xù)跟蹤該方法:
然后調(diào)用當(dāng)前線(xiàn)程的 uncaughtException
分發(fā)異常:
有意思的來(lái)了,如果我們沒(méi)有給當(dāng)前線(xiàn)程設(shè)置 UncaughtExceptionHandler
,則會(huì)將這個(gè)異常交給當(dāng)前線(xiàn)程的 ThreadGroup
處理。如果我們給當(dāng)前線(xiàn)程設(shè)置了 UncaughtExceptionHandler
,則當(dāng)前線(xiàn)程發(fā)生了異常,永遠(yuǎn)也不會(huì)拋給 getDefaultUncaughtExceptionHandler
,該功能適合捕捉當(dāng)前線(xiàn)程異常來(lái)用。
終于回到了我們起初看到的 ThreadGroup.UncaughtExceptionHandler
方法,貼回原來(lái)的圖繼續(xù)分析:
這個(gè)地方會(huì)繼續(xù)判斷 parent
是否為空,parent 是個(gè) ThreadGroup
,ThreadGroup
實(shí)現(xiàn)了 Thread.UncaughtExceptionHandler
接口。這里我就直接說(shuō)答案了,后面再說(shuō) ThreadGroup
和 Thread 的關(guān)系,最終會(huì)走到 system 的 ThreadGroup
,system 的 parent 是個(gè)空,這時(shí)候走 else 分支,獲取 Thread 中的 getDefaultUncaughtExceptionHandler
靜態(tài)變量,觸發(fā) uncaughtException
方法,由于我們?cè)?Activity 中設(shè)置了這個(gè)靜態(tài)變量,所以,我們收到了這個(gè)異常通知。
二、小知識(shí)
1、如何捕獲異常不退出
val default = Thread.getDefaultUncaughtExceptionHandler() Log.e("Uncaught", "Uncaught handler: "+ default) // Uncaught handler: com.android.internal.os.RuntimeInit$KillApplicationHandler@21f02a3 Thread.setDefaultUncaughtExceptionHandler { t, e -> // 將異常回執(zhí)給原注冊(cè)的 handler // default.uncaughtException(t, e) }
捕獲異常后,什么都不處理。但這樣做顯得非常不地道,這樣會(huì)導(dǎo)致其他框架無(wú)法通過(guò)之前設(shè)置的靜態(tài)變量捕獲到異常上報(bào)。我打印了一下 default 是 RuntimeInit
,該類(lèi)在捕獲到異常后,會(huì)做 killProcess
。
2、如何捕獲指定線(xiàn)程異常
val thread = Thread { val a = 1/0 } thread.setUncaughtExceptionHandler { t, e -> Log.e("Uncaught", "Uncaught trace: "+ e.message) } thread.start()
3、ThreadGroup 和 Thread 的關(guān)系結(jié)構(gòu)
Thread
的parent
是在new Thread
的時(shí)候指定的,構(gòu)造可傳自定義的ThreadGroup
,默認(rèn)是使用創(chuàng)建當(dāng)前線(xiàn)程的ThreadGroup
Thread
添加進(jìn)ThreadGroup
的Thread[]
數(shù)組時(shí)機(jī)是在調(diào)用 start 啟動(dòng)線(xiàn)程的時(shí)候做的ThreadGroup 的 parent
是在new ThreadGroup
的時(shí)候指定的,構(gòu)造可傳自定義的ThreadGroup
,默認(rèn)是使用當(dāng)前線(xiàn)程的ThreadGroup
到此這篇關(guān)于A(yíng)ndroid 是如何捕捉 java 異常的的文章就介紹到這了,更多相關(guān)Android 捕捉 java 異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中RecyclerView實(shí)現(xiàn)滑動(dòng)刪除與拖拽功能
這篇文章主要使用了RecyclerView的ItemTouchHelper類(lèi)實(shí)現(xiàn)了Item的拖動(dòng)和刪除功能,ItemTouchHelper是v7包下的一個(gè)類(lèi),下面來(lái)看看詳細(xì)的介紹吧,需要的朋友可以參考學(xué)習(xí)。2017-02-02Android實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單詞本
大家好,本篇文章主要講的是Android實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單詞本,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2022-01-01android notification 的總結(jié)分析
notification是一種出現(xiàn)在任務(wù)欄的提示,特別是在4.0以后notification改進(jìn)了不少,本文內(nèi)容都是基于4.0及4.1以后總結(jié)來(lái)的2013-05-05Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法
這篇文章主要介紹了Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Android獲取當(dāng)前手機(jī)網(wǎng)絡(luò)類(lèi)型(2g、3g、4g、wifi)以及手機(jī)型號(hào)、版本號(hào)代碼
這篇文章主要介紹了Android獲取當(dāng)前手機(jī)網(wǎng)絡(luò)類(lèi)型(2g、3g、4g、wifi)以及手機(jī)型號(hào)、版本號(hào)的相關(guān)資料,需要的朋友可以參考下2016-03-03Android實(shí)現(xiàn)簡(jiǎn)單C/S聊天室應(yīng)用
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單C/S聊天室應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01RecyclerView使用payload實(shí)現(xiàn)局部刷新
這篇文章主要為大家詳細(xì)介紹了RecyclerView使用payload實(shí)現(xiàn)局部刷新,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Android開(kāi)發(fā)之自動(dòng)朗讀TTS用法分析
這篇文章主要介紹了Android開(kāi)發(fā)之自動(dòng)朗讀TTS用法,較為詳細(xì)的分析了TTS的概念、功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-06-06