溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android是怎樣捕捉j(luò)ava異常的

發(fā)布時間:2021-09-24 14:32:33 來源:億速云 閱讀:92 作者:柒染 欄目:開發(fā)技術(shù)

Android是怎樣捕捉j(luò)ava異常的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

一、 java 異常全局捕捉

用于 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 最靠譜:

Android是怎樣捕捉j(luò)ava異常的

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)了這樣的一段代碼,并且還給出了注釋:

Android是怎樣捕捉j(luò)ava異常的

在線程調(diào)用 exit 退出時,如果有未捕獲的異常,則會調(diào)用 Thread.dispatchUncaughtException 方法,然后我們繼續(xù)跟蹤該方法:

Android是怎樣捕捉j(luò)ava異常的

然后調(diào)用當(dāng)前線程的 uncaughtException 分發(fā)異常:

Android是怎樣捕捉j(luò)ava異常的

有意思的來了,如果我們沒有給當(dāng)前線程設(shè)置 UncaughtExceptionHandler ,則會將這個異常交給當(dāng)前線程的 ThreadGroup 處理。如果我們給當(dāng)前線程設(shè)置了 UncaughtExceptionHandler,則當(dāng)前線程發(fā)生了異常,永遠(yuǎn)也不會拋給 getDefaultUncaughtExceptionHandler,該功能適合捕捉當(dāng)前線程異常來用。

終于回到了我們起初看到的 ThreadGroup.UncaughtExceptionHandler 方法,貼回原來的圖繼續(xù)分析:

Android是怎樣捕捉j(luò)ava異常的

這個地方會繼續(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)變量,所以,我們收到了這個異常通知。

二、小知識

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í)給原注冊的 handler
    // default.uncaughtException(t, e)
}

捕獲異常后,什么都不處理。但這樣做顯得非常不地道,這樣會導(dǎo)致其他框架無法通過之前設(shè)置的靜態(tài)變量捕獲到異常上報。我打印了一下 default 是 RuntimeInit,該類在捕獲到異常后,會做 killProcess

2、如何捕獲指定線程異常

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)

Android是怎樣捕捉j(luò)ava異常的

  • 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è)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(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)容。

AI