使用UncaughtExceptionHandler捕捉应用的crash信息

一个Android应用很难做到完全不会出现crash。当应用发生crash时,程序通常会无法继续运行,但如果能知道发生crash的原因,那么就可以修复问题。可是很多时候当产品发布后,用户在使用过程中发生了crash时,很难获取到crash的信息,使得问题代码没法被定位,这非常不利于产品的持续发展。

我们可以通过实现UncaughtExceptionHandler这个接口来捕捉应用的crash信息。当应用发生crash时,就会调用它的uncaughtException方法,我们自己来实现这个方法,就可以在其中对crash信息进行处理,比如我们可以先把它存储到SD卡中,然后找一个合适的时机上传到服务器上。

下面是一个典型的demo,它实现了UncaughtExceptionHandler:

public class CrashHandler implements Thread.UncaughtExceptionHandler{

    private static CrashHandler mInstance = new CrashHandler();
    private static final String PATH = Environment.getExternalStorageDirectory() + "/crash/log/";

    private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
    private Context mContext;

    private CrashHandler(){}

    public static CrashHandler getInstance(){
        return mInstance;
    }

    public void init(Context context){
        mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
        mContext = context.getApplicationContext();
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        try {
            //将crash信息存储到SD卡中
            writeExceptionToSDCard(ex);
            //TODO 将crash信息上传到服务器中
        } catch (IOException e) {
            e.printStackTrace();
        }
        ex.printStackTrace();

        //如果系统有默认的异常处理器,就由系统去结束程序,否则自行结束
        if(mDefaultExceptionHandler != null){
            mDefaultExceptionHandler.uncaughtException(thread, ex);
        }else{
            System.exit(0);
        }
    }

    private void writeExceptionToSDCard(Throwable ex) throws IOException{
        if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            return;
        }
        File dir = new File(PATH);
        if(!dir.exists()){
            dir.mkdirs();
        }
        String currTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date(System.currentTimeMillis()));
        File file = new File(dir, currTime + ".txt");

        try {
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            pw.println(currTime);
            pw.println();
            //写入手机相关的信息
            savePhoneInfo(pw);
            pw.println();
            ex.printStackTrace(pw);
            pw.close();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    private void savePhoneInfo(PrintWriter pw) throws PackageManager.NameNotFoundException {
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
        pw.println("App Version: " + pi.versionName + "_" + pi.versionCode);
        pw.println("Android OS Version: " + Build.VERSION.RELEASE + "_" + Build.VERSION.SDK_INT);
        pw.println("Vendor: " + Build.MANUFACTURER);
        pw.println("Model: " + Build.MODEL);
        pw.println("CPU ABI: " + Build.CPU_ABI);
    }
}

需要注意的是,代码中被catch的异常不会交给UncaughtExceptionHandler去处理,它只能收到未被捕获的异常。

下面来模拟一下手动抛出一个异常的情形:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        CrashHandler.getInstance().init(this);

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                throw new RuntimeException("SELF TEST EXCEPTION");
            }
        });
    }
}

注意必须先要把这个CrashHandler设为默认的异常处理器,再抛出异常。

点击按钮后,CrashHandler捕获了抛出的RuntimeException(“SELF TEST EXCEPTION”),并把它写入到了SD卡中,存储下来的crash信息如下图所示:

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值