Android全局異常捕獲

在開(kāi)發(fā)過(guò)程中我們會(huì)使用try{}catch捕獲一些異常,不過(guò)我們畢竟不能面面俱到,所以總會(huì)有一些異常在我們想不到的位置發(fā)生,然后程序就崩潰了,于是趕緊連上電腦復(fù)現(xiàn)bug,有的可以復(fù)現(xiàn)有的一時(shí)還復(fù)現(xiàn)不了,然后就各種手忙腳亂。

這時(shí)候我們就需要有一個(gè)全局異常捕獲器,當(dāng)有異常發(fā)生時(shí),全局異常捕獲器會(huì)輸出異常信息,然后我們可以設(shè)置將異常信息保存到本地或者是上傳服務(wù)器,方便我們快速的定位問(wèn)題,不用為重新復(fù)現(xiàn)問(wèn)題而搞的焦頭爛額。

一、了解UncaughtExceptionHanlder

這里我們介紹使用UncaughtExceptionHandler來(lái)設(shè)置全局異常捕獲器。首先我們來(lái)看看這個(gè)類(lèi)。

源碼:

@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}

UncaughtExceptionHandler是java.Thread類(lèi)中定義的一個(gè)接口。

作用:
用來(lái)處理在程序中未被捕獲的異常。(如果程序中已經(jīng)自己設(shè)置了try{}catch,則不會(huì)執(zhí)行這個(gè)方法)。

二、實(shí)現(xiàn)方法

1.定義異常捕獲類(lèi)
新建MyCrashHandler 實(shí)現(xiàn)UncaughtExptionHandler接口:

public class MyCrashHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        //在這里處理異常信息
    }
}
  1. 將得到的異常數(shù)據(jù)保存到本地(也可以上傳服務(wù)器,這里根據(jù)需求自行解決)
/**
* 保存錯(cuò)誤信息到文件中
* @param ex
*/
private void saveCrashInfoToFile(Throwable ex) {
    Writer writer = new StringWriter();
    PrintWriter printWriter = new PrintWriter(writer);
    ex.printStackTrace(printWriter);
    Throwable exCause = ex.getCause();
    while (exCause != null) {
        exCause.printStackTrace(printWriter);
        exCause =exCause.getCause();
    }
    printWriter.close();

    long timeMillis = System.currentTimeMillis();
    //錯(cuò)誤日志文件名稱(chēng)
    String fileName = "crash-" + timeMillis + ".log";
    //判斷sd卡可正常使用
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
      //文件存儲(chǔ)位置
      String path = Environment.getExternalStorageDirectory().getPath() + "/crash_logInfo/";
      File fl = new File(path);
       //創(chuàng)建文件夾
        if(!fl.exists()) {
            fl.mkdirs();
        }
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(path + fileName);
            fileOutputStream.write(writer.toString().getBytes());
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

不要忘記配置讀寫(xiě)權(quán)限:

<!-- 往SDCard寫(xiě)入數(shù)據(jù)權(quán)限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 從SDCard讀入數(shù)據(jù)權(quán)限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  1. 將該異常類(lèi)設(shè)置為系統(tǒng)默認(rèn)異常處理類(lèi),然后出現(xiàn)異常時(shí),則該類(lèi)會(huì)處理異常。
//設(shè)置該類(lèi)為系統(tǒng)默認(rèn)處理類(lèi)
Thread.setDefaultUncaughtExceptionHandler(this);
  1. 在Application中使用:
MyCrashHandler mycrashHandler = new MyCrashHandler();
Thread.setDefaultUncaughtExceptionHandler(mycrashHandler);

第3步可以放到Application中,也可以在自身類(lèi)里初始化好。這里只講述思路。

到這里為止,就已經(jīng)完成了全局捕獲器的創(chuàng)建和調(diào)用,如果出現(xiàn)未捕獲的異常,異常信息就會(huì)保存到sd卡內(nèi)。這樣就方便我們的查找。

當(dāng)然上面的代碼只是講解思路,所以使用的時(shí)候,我們需要補(bǔ)充和完善,比如bug信息文件里添加手機(jī)信息,在保存到本地后將文件上傳服務(wù)器等等操作,這些都可以根據(jù)需求自行完善。這里貼出我自己使用的一部分代碼。

public class MyCrashHandler implements Thread.UncaughtExceptionHandler {

    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private Context mcontext;
    private static MyCrashHandler myCrashHandler;

    private MyCrashHandler(){}

    public static synchronized MyCrashHandler newInstance() {
        if(myCrashHandler == null)
            myCrashHandler = new MyCrashHandler();
        return myCrashHandler;
    }

    /**
     * 初始化
     * @param context
     */
    public void init(Context context){
        mcontext = context;
        //系統(tǒng)默認(rèn)處理類(lèi)
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //設(shè)置該類(lèi)為系統(tǒng)默認(rèn)處理類(lèi)
        Thread.setDefaultUncaughtExceptionHandler(this);
    }



    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if(!handleExample(e) && mDefaultHandler != null) { //判斷異常是否已經(jīng)被處理
            mDefaultHandler.uncaughtException(t, e);
        }else {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            //退出程序
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(1);
        }
    }

    /**
     * 提示用戶出現(xiàn)異常
     * 將異常信息保存
     * @param ex
     * @return
     */
    private boolean handleExample(Throwable ex) {
        if(ex == null)
            return false;

        new Thread(() -> {
            Looper.prepare();
            Toast.makeText(mcontext, "很抱歉,程序出現(xiàn)異常,即將退出", Toast.LENGTH_SHORT).show();
            Looper.loop();
        }).start();

        //手機(jī)設(shè)備參數(shù)信息
        collectDeviceInfo(mcontext);
        saveCrashInfoToFile(ex);
        return true;
    }

    /**
     * 設(shè)備信息
     * @param mcontext
     */
    private void collectDeviceInfo(Context mcontext) {


    }


    /**
     * 保存錯(cuò)誤信息到文件中
     * @param ex
     */
    private void saveCrashInfoToFile(Throwable ex) {
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable exCause = ex.getCause();
        while (exCause != null) {
            exCause.printStackTrace(printWriter);
            exCause = exCause.getCause();
        }
        printWriter.close();

        long timeMillis = System.currentTimeMillis();
        //錯(cuò)誤日志文件名稱(chēng)
        String fileName = "crash-" + timeMillis + ".log";
        //判斷sd卡可正常使用
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //文件存儲(chǔ)位置
            String path = Environment.getExternalStorageDirectory().getPath() + "/crash_logInfo/";
            File fl = new File(path);
            //創(chuàng)建文件夾
            if(!fl.exists()) {
                fl.mkdirs();
            }
            try {
                FileOutputStream fileOutputStream = new FileOutputStream(path + fileName);
                fileOutputStream.write(writer.toString().getBytes());
                fileOutputStream.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 穩(wěn)定性測(cè)試是保障客戶端穩(wěn)定性的一種手段,致力于提前發(fā)現(xiàn)問(wèn)題,收集更多異常信息,復(fù)現(xiàn)線上閃退。當(dāng)Android客戶端...
    one_step123閱讀 8,440評(píng)論 0 0
  • 全局異常捕獲 UncaughtExceptionHandler 當(dāng)app上線后,可能存在某些異常導(dǎo)致程序崩潰,開(kāi)...
    Teprinciple閱讀 3,099評(píng)論 0 1
  • 一、作用 當(dāng)程序面對(duì)那些未捕獲異常時(shí),我們進(jìn)行一些處理,幫助自己分析解決問(wèn)題。 二、使用 1.對(duì)未手動(dòng)捕獲異常的處...
    四喜湯圓閱讀 760評(píng)論 0 0
  • 在全局入口Application初始化 //日志捕獲緩存類(lèi)
    luchefg閱讀 2,087評(píng)論 1 3
  • 1. 概述 本文主要講解如何自定義 Android 全局異常捕獲,以及如何通過(guò) Dialog 展示異常信息并將異常...
    極速24號(hào)閱讀 2,853評(píng)論 0 21

友情鏈接更多精彩內(nèi)容