Android 全局捕獲異常簡(jiǎn)單實(shí)現(xiàn)

直接上代碼

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static CrashHandler INSTANCE;

    private Context mContext;
    private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;
    // 用來(lái)存儲(chǔ)設(shè)備信息和異常信息
    private Map<String, String> mErrorInfoMap = new LinkedHashMap<>();
    // 用于格式化日期,作為日志文件名的一部分
    private SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

    private String mDivider = "==============divider==============";

    private CrashHandler() {
    }

    public static CrashHandler getInstance(Context context) {
        if (INSTANCE == null) {
            INSTANCE = new CrashHandler();
            INSTANCE.mContext = context;
            INSTANCE.mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
            Thread.setDefaultUncaughtExceptionHandler(INSTANCE);
        }
        return INSTANCE;
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultUncaughtExceptionHandler != null) {
            mDefaultUncaughtExceptionHandler.uncaughtException(thread, ex);
        } else {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // DLog.e("error : ", e);
            }

            // 退出程序,注釋下面的重啟啟動(dòng)程序代碼
//            android.os.Process.killProcess(android.os.Process.myPid());
//            System.exit(1);
            ex.printStackTrace();


            // 重新啟動(dòng)程序,注釋上面的退出程序
            restartApp();
        }
    }

    //異常崩潰  重新啟動(dòng)
    private void restartApp() {
        Intent intent = new Intent();
        intent.setClass(mContext, SplashActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
       
    }

    public boolean handleException(Throwable ex) {
        if (null == ex) {
            return false;
        }
        // 使用 Toast 來(lái)顯示異常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
               // ToastUtils.show(mContext, "出現(xiàn)未知錯(cuò)誤");
                Looper.loop();
            }
        }.start();
        //記錄設(shè)備參數(shù)信息
        // collectDeviceInfo(mContext);
        //保存日志文件
        // saveCrashInfo2File(ex);

        return true;
    }

    /**
     * 收集設(shè)備參數(shù)信息
     *
     * @param ctx
     */
    public void collectDeviceInfo(Context ctx) {
        try {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);

            if (pi != null) {
                String versionName = pi.versionName == null ? "null" : pi.versionName;
                String versionCode = pi.versionCode + "";
                mErrorInfoMap.put("versionName", versionName);
                mErrorInfoMap.put("versionCode", versionCode);
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            //  DLog.e(e);
        }

        mErrorInfoMap.put("=", mDivider);

        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                mErrorInfoMap.put(field.getName(), field.get(null).toString());
                // DLog.v(field.getName() + " : " + field.get(null));
            } catch (Exception e) {
                //  DLog.e("an error occured when collect crash info ", e);
            }
        }


    }

    /**
     * 保存錯(cuò)誤信息到文件中
     * ?*
     *
     * @param ex
     * @return 返回文件名稱, 便于將文件傳送到服務(wù)器
     */
    private String saveCrashInfo2File(Throwable ex) {
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : mErrorInfoMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key + "=" + value + "\n");
        }

        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();

        sb.append(mDivider).append("\n");

        sb.append(result);
        try {
            long timestamp = System.currentTimeMillis();
            String time = mSimpleDateFormat.format(new Date());
            String fileName = "crash-" + time + "-" + timestamp + ".log";
            String logDir = "log";
            File path = new File(mContext.getExternalCacheDir() + File.separator + logDir + File.separator + fileName);
            if (!path.getParentFile().exists()) {
                path.getParentFile().mkdirs();
            }
            FileOutputStream fos = new FileOutputStream(path);
            fos.write(sb.toString().getBytes());
            fos.close();
            return fileName;
        } catch (Exception e) {
            //  DLog.e("an error occured while writing file... ", e);
        }

        return null;
    }
}


ApplicationonCreate使用

 //初始化全局異常處理,崩潰自啟
 CrashHandler.getInstance(this);

?著作權(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)書系信息發(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,442評(píng)論 0 0
  • 大家都知道,現(xiàn)在安裝Android系統(tǒng)的手機(jī)版本和設(shè)備千差萬(wàn)別,在模擬器和自己的android手機(jī)上運(yùn)行良好的程序...
    Orz013閱讀 3,869評(píng)論 0 4
  • 都遇到過(guò)APP使用崩潰的情況,尤其是在線上的崩潰,我們無(wú)法看到崩潰信息,此時(shí)就需要對(duì)崩潰信息進(jìn)行收集。之前用的都是...
    好名字都已經(jīng)讓人起了閱讀 867評(píng)論 0 1
  • 調(diào)用部分: 在Application的onCreate()方法中調(diào)用下面三行代碼: Utils.init(getA...
    賓哥來(lái)啦閱讀 608評(píng)論 0 0
  • 應(yīng)用的crash是讓人很蛋疼的問(wèn)題,在開發(fā)測(cè)試的時(shí)候還能根據(jù)日志輸出什么的進(jìn)行排查修復(fù),但是應(yīng)用發(fā)布以后,用戶的隨...
    我是午飯閱讀 1,878評(píng)論 0 11

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