public class CrashHandlerManager { private static CrashHandlerManager instance; private static Context mContext; private CrashHandlerManager(){} public static CrashHandlerManager getInstance(Context context){ if(instance==null){ mContext=context.getApplicationContext(); instance=new CrashHandlerManager(); } return instance; } public void init(){ Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){ @Override public void uncaughtException(Thread t, Throwable e) { handleException(e); //判斷當前線程是不是主線程 if(t== Looper.getMainLooper().getThread()){ handleMainThread(e); } } }); } private void handleMainThread(Throwable e) { while (true) { try { Looper.loop(); } catch (Throwable throwable) { handleException(throwable); } } } private void handleException(Throwable e) { //寫入錯誤日誌 //上傳日誌 } } 複製代碼
你們很容易就看懂了這個類,保證應用永不崩潰關鍵在於handleMainThread這個方法。一旦主線程中出現異常就會致使Looper.loop沒法正常輪詢,看過源碼的都知道Looper.loop是執行在ActivityThread的main方法中,只會執行一次,而Looper.loop不能正常輪詢就會致使應用崩潰。其中利用Looper.loop是一個阻塞方法的特性,咱們能夠給它外面套上一層無限循環,一旦出錯就會從新啓動輪詢。bash
若是想了解Thread.setDefaultUncaughtExceptionHandler爲何能夠阻止應用crash,能夠查看前一篇文章markdown
經過Thread.setDefaultUncaughtExceptionHandler阻止程序崩潰的源碼解析ide
因爲各個公司對錯誤信息處理級別不一樣,針對錯誤數據的封裝也會各不同,我只是提一點我的小建議和心得。oop
1.把錯誤信息作相應的拆分和拼裝,生成規定格式的錯誤數據,寫入日誌文件,日誌文件能夠是區間日誌也能夠是即刻日誌(由於錯誤信息要分等級,若是是重大bug須要及時上傳,並經過短信和郵件及時通知開發人員)post
2.存儲當前設備信息(用戶,廠商,系統,版本)到錯誤日誌性能
3.既然本地有錯誤日誌確定要上傳,不過上傳的間隔確定要控制,畢竟上傳耗費性能(看大家後臺須要刷新錯誤日誌的間隔,)spa
4.上傳完成記得及時清除線程
5.後臺構建錯誤監控模塊(不單單針對應用的bug也有多是部分接口功能異常等),針對重大bug,對應用bug功能及時進行動態屏蔽(對應用內部的功能作接口控制),而後用熱修復或者應用更新解決問題。日誌