美文网首页读书点点
Android全局异常捕获

Android全局异常捕获

作者: 君天涯 | 来源:发表于2019-05-15 17:25 被阅读0次

    在开发过程中我们会使用try{}catch捕获一些异常,不过我们毕竟不能面面俱到,所以总会有一些异常在我们想不到的位置发生,然后程序就崩溃了,于是赶紧连上电脑复现bug,有的可以复现有的一时还复现不了,然后就各种手忙脚乱。

    这时候我们就需要有一个全局异常捕获器,当有异常发生时,全局异常捕获器会输出异常信息,然后我们可以设置将异常信息保存到本地或者是上传服务器,方便我们快速的定位问题,不用为重新复现问题而搞的焦头烂额。

    一、了解UncaughtExceptionHanlder

    这里我们介绍使用UncaughtExceptionHandler来设置全局异常捕获器。首先我们来看看这个类。

    源码:

    @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类中定义的一个接口。

    作用:
    用来处理在程序中未被捕获的异常。(如果程序中已经自己设置了try{}catch,则不会执行这个方法)。

    二、实现方法

    1.定义异常捕获类
    新建MyCrashHandler 实现UncaughtExptionHandler接口:

    public class MyCrashHandler implements Thread.UncaughtExceptionHandler {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            //在这里处理异常信息
        }
    }
    
    1. 将得到的异常数据保存到本地(也可以上传服务器,这里根据需求自行解决)
    /**
    * 保存错误信息到文件中
    * @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();
        //错误日志文件名称
        String fileName = "crash-" + timeMillis + ".log";
        //判断sd卡可正常使用
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
          //文件存储位置
          String path = Environment.getExternalStorageDirectory().getPath() + "/crash_logInfo/";
          File fl = new File(path);
           //创建文件夹
            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();
            }
        }
    }
    

    不要忘记配置读写权限:

    <!-- 往SDCard写入数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 从SDCard读入数据权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
    1. 将该异常类设置为系统默认异常处理类,然后出现异常时,则该类会处理异常。
    //设置该类为系统默认处理类
    Thread.setDefaultUncaughtExceptionHandler(this);
    
    1. 在Application中使用:
    MyCrashHandler mycrashHandler = new MyCrashHandler();
    Thread.setDefaultUncaughtExceptionHandler(mycrashHandler);
    

    第3步可以放到Application中,也可以在自身类里初始化好。这里只讲述思路。

    到这里为止,就已经完成了全局捕获器的创建和调用,如果出现未捕获的异常,异常信息就会保存到sd卡内。这样就方便我们的查找。

    当然上面的代码只是讲解思路,所以使用的时候,我们需要补充和完善,比如bug信息文件里添加手机信息,在保存到本地后将文件上传服务器等等操作,这些都可以根据需求自行完善。这里贴出我自己使用的一部分代码。

    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;
            //系统默认处理类
            mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
            //设置该类为系统默认处理类
            Thread.setDefaultUncaughtExceptionHandler(this);
        }
    
    
    
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            if(!handleExample(e) && mDefaultHandler != null) { //判断异常是否已经被处理
                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);
            }
        }
    
        /**
         * 提示用户出现异常
         * 将异常信息保存
         * @param ex
         * @return
         */
        private boolean handleExample(Throwable ex) {
            if(ex == null)
                return false;
    
            new Thread(() -> {
                Looper.prepare();
                Toast.makeText(mcontext, "很抱歉,程序出现异常,即将退出", Toast.LENGTH_SHORT).show();
                Looper.loop();
            }).start();
    
            //手机设备参数信息
            collectDeviceInfo(mcontext);
            saveCrashInfoToFile(ex);
            return true;
        }
    
        /**
         * 设备信息
         * @param mcontext
         */
        private void collectDeviceInfo(Context mcontext) {
    
    
        }
    
    
        /**
         * 保存错误信息到文件中
         * @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();
            //错误日志文件名称
            String fileName = "crash-" + timeMillis + ".log";
            //判断sd卡可正常使用
            if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                //文件存储位置
                String path = Environment.getExternalStorageDirectory().getPath() + "/crash_logInfo/";
                File fl = new File(path);
                //创建文件夹
                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();
                }
            }
        }
    }
    
    

    相关文章

      网友评论

        本文标题:Android全局异常捕获

        本文链接:https://www.haomeiwen.com/subject/fatwaqtx.html