Android UncaughtExceptionHandler捕獲Crash

Android系統的“程序異常退出”,給應用的用戶體驗造成不良影響。爲了捕獲應用運行時異常並給出友好提示,便可繼承UncaughtExceptionHandler類來處理。通過Thread.setDefaultUncaughtExceptionHandler()方法將異常處理類設置到線程上即可。重寫uncaughtException方法,注意只有程序未捕獲的異常纔會調用這裏,如果程序捕獲了,就不會了。

package demo.lbb.anotest;

import android.content.Context;
import java.lang.Thread.UncaughtExceptionHandler;
/**
 * Created by liaobinbin on 2015/12/13.
 */
public class CrashHandler implements UncaughtExceptionHandler {
    private static CrashHandler INSTANCE = new CrashHandler();
    private Context mContext;
    private UncaughtExceptionHandler mDefaultHandler;

    private CrashHandler() {
    }

    public static CrashHandler getInstance() {
        return INSTANCE;
    }

    public void init(Context ctx) {
        mContext = ctx.getApplicationContext();//防止activity釋放不了,導致OOM
        //mContext = ctx; 如果想顯示dialog的話,就不能用ApplicationContext了
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); //獲取系統默認的異常處理器
        //Sets the default uncaught exception handler. This handler is invoked in case any Thread dies due to an unhandled exception.只捕獲爲處理的異常,回調uncaughtException方法
        //設置異常處理器爲this,注意要在getDefaultUncaughtExceptionHandler後調用,否則前面的結果mDefaultHandler就是this了,那麼uncaughtException無限循環調用
        Thread.setDefaultUncaughtExceptionHandler(this); 
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        QDLog.d("uncaughtException");
        handleException(ex);

        //系統提供了默認的異常處理器,則系統結束程序,否則自己結束自己,實際測試mDefaultHandler不爲null的,所以還是會出現“停止運行”框的,系統默認行爲
        if (mDefaultHandler != null) {
            QDLog.d("mDefaultHandler is not null");
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(10);
        }
    }

    /**
     * 自定義錯誤處理,收集錯誤信息 發送錯誤報告等操作均在此完成. 開發者可以根據自己的情況來自定義異常處理邏輯
     *
     * @param ex
     * @return true:如果處理了該異常信息;否則返回false
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return true;
        }
        QDLog.d("handleException: " + ex);
        //1. 可以把ex存儲在存儲卡中
        //2. 實際開發更多的把crash信息上報給服務器,供開發人員分析,不只記錄crash信息,同時還記錄手機的機型,型號等方便開發人員復現
        //3. 這裏還可以彈出一個dialog,提醒用戶,發生了異常

        return true;
    }
}

public class BaseApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(this);
    }
}

    //Activity中模擬一下
    @OnClick(R.id.but)
    void onClick() {
        throw new RuntimeException("自定義異常,同時程序未捕獲");
    }

實際結果:
D/LiaBin: uncaughtException
D/LiaBin: handleException: java.lang.RuntimeException: 自定義異常,同時程序未捕獲
D/LiaBin: mDefaultHandler is not null
出現“停止運行”框的

註釋該行:

        if (mDefaultHandler != null) {
            QDLog.d("mDefaultHandler is not null");
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(10);
        }

那麼是不會出現出現“停止運行”框,因爲未捕獲的異常被我們自己處理了,不經過系統。所以不出現“停止運行”框

一開始以爲子線程發生異常是沒法捕獲的

    @OnClick(R.id.but)
    void onClick() {
        new Thread() {
            @Override
            public void run() {
                throw new RuntimeException("自定義異常,同時程序未捕獲");
            }
        }.start();
    }

後來測試了一下,也是可以捕獲的,因爲
Thread.setDefaultUncaughtExceptionHandler(this);爲該進程設置了默認的未捕獲異常處理器,注意是進程,而不是該線程,因爲defaultUncaughtHandler
是靜態屬性的。。。

    /**
     * Holds the default handler for uncaught exceptions, in case there is one.
     */
    private static UncaughtExceptionHandler defaultUncaughtHandler;
    public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
        Thread.defaultUncaughtHandler = handler;
    }

defaultUncaughtHandler是靜態屬性,全局的,所以設置了一次,所有線程包括子線程,main線程的未捕獲的異常都會被UncaughtExceptionHandler處理的

發佈了78 篇原創文章 · 獲贊 9 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章