UncaughtException 的使用

       

JVM为我们提供了线程的未捕获异常处理机制,通过Thread的setUncaughtExceptionHandler方法:

               public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)

通过该方法给某个thread设置一个UncaughtExceptionHandler,可以确保在该线程出现异常时能通过回调UncaughtExceptionHandler接口的public void uncaughtException(Thread t, Throwable e) 方法来处理异常,这样的好处或者说目的是可以在线程代码边界之外(Thread的run()方法之外),有一个地方能处理未捕获异常。但是要特别明确的是:虽然是在回调方法中处理异常,但这个回调方法在执行时依然还在抛出异常的这个线程中!另外还要特别说明一点:如果线程是通过线程池创建,线程异常发生时UncaughtExceptionHandler接口不一定会立即回调。

 

当遇到未捕获异常的情况下,记录android程序无缘无故crash,自定义CrashExceptionHandle implements UncaughtExceptionHandler,处理未捕获异常,并将日志持久化到文件中,有助于排查bug。

 

package xyz.o88o.crash;

import android.content.Context;

import org.json.JSONObject;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DateFormat;
import java.text.SimpleDateFormat;


import xyz.o88o.AppContext;
import xyz.o88o.account.AccountUtils;
import xyz.o88o.utils.DeviceUtil;
import xyz.o88o.utils.FileUtil;
import xyz.o88o.utils.LogUtil;


public class CrashExceptionHandle implements UncaughtExceptionHandler {


    private final static String TAG = CrashExceptionHandle.class.getSimpleName();
    public final static String KEY_JSON_ERROR_STACK = "error_stack";


    Context mContext;
    // 用于格式化日期,作为日志文件名的一部分
    private DateFormat formatter = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
    // CrashHandler实例
    private static CrashExceptionHandle instance;
    // 系统默认的UncaughtException处理类
    private UncaughtExceptionHandler mDefaultHandler;


    private CrashExceptionHandle() {
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        // 设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }


    public synchronized static CrashExceptionHandle getIntance() {
        if (instance == null) {
            instance = new CrashExceptionHandle();
        }
        return instance;
    }


    public void init(Context ctx) {
        mContext = ctx;
    }


    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        handleException(thread, ex);
        mDefaultHandler.uncaughtException(thread, ex);// 系统默认异常处理器
    }


    private boolean handleException(final Thread thread, final Throwable ex) {
        if (ex == null) {
            return false;
        }
        LogUtil.e(TAG, "crash", ex);
        new Thread() {
            @Override
            public void run() {
                saveCrashLog2File(ex);
            }
        }.start();
        return true;
    }


    private void saveCrashLog2File(Throwable ex) {
        String time = formatter.format(System.currentTimeMillis());
        String filename = "crash_" + time + ".log";
        JSONObject messageRootObject = new JSONObject();
        try {
            messageRootObject.put("device_id", DeviceUtil.mDeviceId);
            messageRootObject.put("@timestamp", time);
            messageRootObject.put("uid", AccountUtils.getAccountUID(AppContext.getContext()));
            messageRootObject.put("platform", DeviceUtil.mOs);
            messageRootObject.put("error", ex.toString());
            messageRootObject.put(KEY_JSON_ERROR_STACK, buildStackTraceFromException(ex));
        } catch (Exception e) {
            e.printStackTrace();
        }
        StringBuilder builder = new StringBuilder();
        builder.append(messageRootObject.toString()).append("\n");
        write(filename, builder.toString(), false);
    }


    private String buildStackTraceFromException(Throwable ex) {
        String context = null;
        if (ex != null) {
            context = ex.toString() + "\n";
            StackTraceElement[] ste = ex.getStackTrace();
            for (int i = 0; i < ste.length; i++) {
                context += " at " + ste[i].toString() + "\n";
            }
            Throwable cex = ex.getCause();
            if (cex != null) {
                ste = cex.getStackTrace();
                context += "Cased by: " + cex.toString() + "\n";
                for (int i = 0; i < ste.length; i++) {
                    context += " at " + ste[i].toString() + "\n";
                }
            }
        }
        return context;
    }


    /**
     * 写入文件,并将文件路径写入tray
     *
     * @param fileName
     * @param content
     * @param append
     */
    private void write(String fileName, String content, boolean append) {
        File file = new File(FileUtil.SDCARD_STORAGE_PATH_LOG, fileName);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdir();
        }
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
            }
        }
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, append)));
            out.write(content);
        } catch (Exception e) {


        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                    out = null;
                }
            } catch (IOException e) {


            }
        }
    }
}

深圳逆时针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值