標籤:
註:本內容僅是工作筆記,用於備忘,未貼出具體代碼。描述不清請見諒。
===================================================================================================
問題描述與分析:
為了擷取Crash日誌,項目中實現了UncaughtExceptionHandler介面對未知異常進行捕獲並上傳到伺服器中,同時停止App運行。在Android5.0以下系統一直未出現過問題,但是突然發現在Android 5.0以上的機器中這段代碼出現了java.lang.InternalError: Thread starting during runtime shutdown(更多異常資訊見最後部分的附錄),在stackoverflow中得到了一些協助:這個問題是因為線程開啟的太晚了!
什麼時候開啟線程才算得上“太晚了”呢? 在我的項目中UncaughtExceptionHandler實作類別捕獲到異常時(也就是UncaughtExceptionHandler介面的uncaughtException方法執行時),開啟了一個線程用於上傳崩潰日誌,而線上程中上傳崩潰日誌時建立了HttpClient發送網路請求。HttpClient建立時設定了ThreadSafeClientConnManager來管理串連,而在ThreadSafeClientConnManager的源碼中又一次開啟了線程!也就是說,uncaughtException方法執行時在開啟的線程中又開啟了新的線程,這樣可能會導致uncaughtException方法在執行完成時,“線程中的線程”才start(),而據說uncaughtException方法執行完成後ART環境就shutdown了(uncaughtException方法結束時ART是否會真的shutdown,這一點有待考證,筆者也僅是從其他非官方資料中得知),這種情況下就會拋出java.lang.InternalError: Thread starting during runtime shutdown。
為了驗證這個問題,編寫了一段簡單的代碼:實現UncaughtExceptionHandler的uncaughtException方法,在uncaughtException方法中開啟一個線程,在這個線程中再開一線程,同時在MainActivity中故意製造一個異常發生,此時果然會出現java.lang.InternalError: Thread starting during runtime shutdown(並不是每次都出現,因為如果uncaughtException方法執行結束之前,兩個線程都完成start(),此問題就不會出現)。
解決方案:
避免在uncaughtException方法中出現線程嵌套:針對我的項目,不再去線上程中建立HttpClient(因為HttpClient建立時還會開啟線程,這就造成了線程中再次開啟線程),而是先建立HttpClient對象,再線上程中使用HttpClient對象。這樣就可以確保uncaughtException方法結束之前HttpClient已經被建立,HttpClient中開啟線程也就不會有問題。
附異常資訊:
java.lang.InternalError: Thread starting during runtime shutdown at java.lang.Thread.nativeCreate(Native Method) at java.lang.Thread.start(Thread.java:1042) at org.apache.http.impl.conn.tsccm.AbstractConnPool.enableConnectionGC(AbstractConnPool.java:140) at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.createConnectionPool(ThreadSafeClientConnManager.java:120) at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.<init>(ThreadSafeClientConnManager.java:98) at
Thread starting during runtime shutdown問題的解決