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處理的