注:本內容僅是工作筆記,用於備忘,未貼出具體代碼。描述不清請見諒。
===================================================================================================
問題描述與分析:
為了獲取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