您好,登錄后才能下訂單哦!
Android是怎樣捕捉j(luò)ava異常的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
用于 java 異常全局捕捉代碼:
val default = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { t, e -> // 處理異常 Log.e("Uncaught", "exception message : "+ e.message) // 將異?;貓?zhí)給原注冊的 handler default.uncaughtException(t, e) }
以上是很簡單的一段代碼,經(jīng)常被用于 java 異常全局捕捉,但我的疑問是,他是怎么實現(xiàn)全局捕捉的,帶著這樣的疑問,我們來扒一下代碼看看。
順藤摸瓜,我們看看靜態(tài)方法 getDefaultUncaughtExceptionHandler
是被誰調(diào)用的,看了下所有的類調(diào)用的類,唯有 ThreadGroup
最靠譜:
在 parent
為空的情況下,就會調(diào)用 getDefaultUncaughtExceptionHandler
來回調(diào)異常,然后繼續(xù)順藤摸瓜,看看 ThreadGroup
的 uncaughtException
是被誰觸發(fā)的,搜了一個圈,沒有一個靠譜的。在我躊躇時,順帶瞄了一眼注釋,奇跡發(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)一個未捕獲的異常導(dǎo)致線程組中的線程停止時,JVM 會調(diào)用該方法。那我們就去搜搜 jvm 的源碼,看看是怎么觸發(fā)這個方法的。
在 Hotspot
虛擬機(jī)源碼的 thread.cpp
中的 JavaThread::exit
方法發(fā)現(xiàn)了這樣的一段代碼,并且還給出了注釋:
在線程調(diào)用 exit
退出時,如果有未捕獲的異常,則會調(diào)用 Thread.dispatchUncaughtException
方法,然后我們繼續(xù)跟蹤該方法:
然后調(diào)用當(dāng)前線程的 uncaughtException
分發(fā)異常:
有意思的來了,如果我們沒有給當(dāng)前線程設(shè)置 UncaughtExceptionHandler
,則會將這個異常交給當(dāng)前線程的 ThreadGroup
處理。如果我們給當(dāng)前線程設(shè)置了 UncaughtExceptionHandler
,則當(dāng)前線程發(fā)生了異常,永遠(yuǎn)也不會拋給 getDefaultUncaughtExceptionHandler
,該功能適合捕捉當(dāng)前線程異常來用。
終于回到了我們起初看到的 ThreadGroup.UncaughtExceptionHandler
方法,貼回原來的圖繼續(xù)分析:
這個地方會繼續(xù)判斷 parent
是否為空,parent 是個 ThreadGroup
,ThreadGroup
實現(xiàn)了 Thread.UncaughtExceptionHandler
接口。這里我就直接說答案了,后面再說 ThreadGroup
和 Thread 的關(guān)系,最終會走到 system 的 ThreadGroup
,system 的 parent 是個空,這時候走 else 分支,獲取 Thread 中的 getDefaultUncaughtExceptionHandler
靜態(tài)變量,觸發(fā) uncaughtException
方法,由于我們在 Activity 中設(shè)置了這個靜態(tài)變量,所以,我們收到了這個異常通知。
val default = Thread.getDefaultUncaughtExceptionHandler() Log.e("Uncaught", "Uncaught handler: "+ default) // Uncaught handler: com.android.internal.os.RuntimeInit$KillApplicationHandler@21f02a3 Thread.setDefaultUncaughtExceptionHandler { t, e -> // 將異常回執(zhí)給原注冊的 handler // default.uncaughtException(t, e) }
捕獲異常后,什么都不處理。但這樣做顯得非常不地道,這樣會導(dǎo)致其他框架無法通過之前設(shè)置的靜態(tài)變量捕獲到異常上報。我打印了一下 default 是 RuntimeInit
,該類在捕獲到異常后,會做 killProcess
。
val thread = Thread { val a = 1/0 } thread.setUncaughtExceptionHandler { t, e -> Log.e("Uncaught", "Uncaught trace: "+ e.message) } thread.start()
Thread
的 parent
是在 new Thread
的時候指定的,構(gòu)造可傳自定義的 ThreadGroup
,默認(rèn)是使用創(chuàng)建當(dāng)前線程的 ThreadGroup
Thread
添加進(jìn) ThreadGroup
的 Thread[]
數(shù)組時機(jī)是在調(diào)用 start 啟動線程的時候做的
ThreadGroup 的 parent
是在 new ThreadGroup
的時候指定的,構(gòu)造可傳自定義的 ThreadGroup
,默認(rèn)是使用當(dāng)前線程的 ThreadGroup
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。