開發安卓的小伙伴都遇到過APP突然崩潰,無響應的情況.如果發生在自己手中,那么還可以通過IDE查看錯誤日志,但是實際都是發生在用戶手中,那么這個時候產生崩潰,無響應ANR異常就很麻煩.無從下手.因此,需要全局異常捕獲.也就是對未知異常,程序員沒有處理的異常進行處理,記錄等便於分析查找原因.
首先,新建一個類 MyCatchException.Java
package com.linfeng.activity; import android.content.Context; import android.os.Looper; import android.util.Log; import android.widget.Toast; import com.linfeng.util.Util; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; /** * Created by Linfeng on 2019/05/14. */ //全部錯誤捕捉器 public class MyCatchException implements Thread.UncaughtExceptionHandler { //本類實例 private static MyCatchException mInstance; //系統默認的uncatchException private Thread.UncaughtExceptionHandler mDefaultException; private Context mContext; //保證只有一個實例 public MyCatchException() { } //單例模式 public static MyCatchException getInstance() { if (mInstance == null) { mInstance = new MyCatchException(); } return mInstance; } //獲取系統默認的異常處理器,並且設置本類為系統默認處理器 public void init(Context ctx) { this.mContext = ctx; mDefaultException = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } //自定義錯誤處理器 private boolean handlerException(Throwable ex) { if (ex == null) { //如果已經處理過這個Exception,則讓系統處理器進行后續關閉處理 return false; } //獲取錯誤原因 Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); ex.printStackTrace(printWriter); Throwable cause = ex.getCause(); while (cause!=null){ cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); String result = writer.toString(); final String msg= result ; new Thread() { public void run() { // Toast 顯示需要出現在一個線程的消息隊列中 Looper.prepare(); Toast.makeText(mContext, "程序出錯:" + msg.toString(), Toast.LENGTH_LONG).show(); //將異常記錄到本地的數據庫或者文件中.或者直接提交到后台服務器 Util.writeLog("全局異常",msg); Looper.loop(); } ; }.start(); return true; } @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handlerException(ex) && mDefaultException != null) { // 如果用戶沒有處理則讓系統默認的異常處理器來處理 mDefaultException.uncaughtException(thread, ex); } else { //否則自己進行處理 try { //Sleep 來讓線程停止一會是為了顯示Toast信息給用戶,然后Kill程序 Thread.sleep(3000); } catch (InterruptedException e) { Util.writeLog("全局異常",e.getMessage()); Log.d("2635", "uncaughtException: "+e.getMessage()); }catch (Exception e){ Util.writeLog("全局異常",e.getMessage()); Log.d("2635", "Exception: "+e.getMessage()); } //如果不關閉程序,會導致程序無法啟動,需要完全結束進程才能重新啟動 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(10); } } }
然后在APP的application中注冊,但是由於一般application都可能用了,或者不方便修改.一般采用在APP的第一個Activity中進行注冊,那么我這里在我第一個Activity,也就是SplashActivity頁面的onCreate方法中添加這兩句代碼
MyCatchException mException=MyCatchException.getInstance(); mException.init(getApplicationContext()); //注冊
這樣就完成了,當我們app有沒有處理的異常時,就會自動幫我們捕獲異常.可以做一個測試.
比如,在MainActivity中隨便拋出一個異常,比如數組越界,空指針異常等去測試是否能捕獲這個異常.
