Android-构建全局的异常捕捉类

本文介绍了如何构建Android全局的异常捕捉类,通过实现Thread.UncaughtExceptionHandler接口并使用单例模式,结合Application进行初始化。在uncaughtException方法中收集异常信息,如手机型号和版本,保存到SD卡,并提供获取异常文件的方法。异常发生时,可在第二次启动时上传异常信息到服务器,便于快速修复bug。此外,提到了友盟和Bugly等第三方bug监控平台作为替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

整体思路
构建Android应用全局的异常信息捕捉类,当App Crash的时候,能够获取崩溃信息,包括ExceptionMessage,手机信息,版本信息等。然后写入文件存到手机sd卡中。当应用下次开启的时候读取文件上传服务器,为后期的热修复做准备。
  • 首先新建一个ExceptionCrashHandler类实现Thread.UncaughtExceptionHandler接口,并重写uncaughtException(Thread t, Throwable e)方法,这个方法当有异常发生的时候会被回调。
  • ExceptionCrashHandler整个应用有一份即可,所以可以使用单例模式要构建。
private static ExceptionCrashHandler mInstance;
        private Context mContext;
        private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;

        public static ExceptionCrashHandler getInstance() {
            if (mInstance == null) {
                //同步锁,处理并发问题
                synchronized (ExceptionCrashHandler.class) {
                    if (mInstance == null) {
                        mInstance = new ExceptionCrashHandler();
                    }
                }
            }
            return mInstance;
        }

      public void init(Context context) {
              mContext = context;
              //设置全局的异常类为本类
              Thread.currentThread().setUncaughtExceptionHandler(this);
              //获取系统默认的异常处理
              mDefaultExceptionHandler =              Thread.currentThread().getDefaultUncaughtExceptionHandler();
          }
  • 在全局的Application中初始化。
 ExceptionCrashHandler.getInstance().init(this);
  • 在uncaughtException方法中去做一些信息的收集工作
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            //全局异常
            Logger.e("报异常了!");
            //拿到异常信息,写到本地文件,包括异常信息,机型信息,当前版本等
            //1,异常信息
            //2,应用信息,包名  版本号
            //3,手机机型信息
            //4,保存当前文件,当应用再次启动的时候再去上传。   上传文件不能在这里处理

            String crashFileName = saveInfo2SD(e);

            Logger.d("CrashFileName--->" + crashFileName);

            //缓存崩溃日志
            cacheCrashLog(crashFileName);

            //系统默认的处理方式
            mDefaultExceptionHandler.uncaughtException(t, e);
        }
  • 保存信息到SD卡中
        /**
         * 保存异常信息,软件信息,设备信息到sd卡中
         *
         * @param e
         * @return
         */
        private String saveInfo2SD(Throwable e) {
            String fileName = null;
            StringBuffer stringBuffer = new StringBuffer();
            Map<String, String> simpleInfo = getSimpleInfo(mContext);
            //循环获取map中的键值对,拼接到StringBuffer中
            for (Map.Entry<String, String> entry : simpleInfo.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                stringBuffer.append(key).append("=").append(value).append("\n");
            }

            //拼接系统异常信息
            stringBuffer.append(getExceptionInfo(e));

            //将数据写入到Sd卡中
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                //sd卡可用
                File dir = new File(mContext.getFilesDir() + File.separator + "crash" + File.separator);

                //删除之前的异常信息
                if (dir.exists()) {
                    deleteDir(dir);
                }

                //在创建新的文件夹
                if (!dir.exists()) {
                    dir.mkdirs();
                }

                try {
                    fileName = dir.toString() + File.separator + getAssignTime("yyyy_MM_dd_HH_mm") + ".txt";
                    FileOutputStream fos = new FileOutputStream(fileName);
                    fos.write(stringBuffer.toString().getBytes());
                    fos.flush();
                    fos.close();

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            return fileName;
        }
  • 获取手机信息可以通过反射,获取Build类中的字段信息。这里面可以拿到手机型号,版本信息。可能某些bug是在特定机型上才出现。
        /**
         * 利用反射Build类获取手机信息
         *
         * @return
         */
        private String getMobileInfo() {
            StringBuffer stringBuffer = new StringBuffer();
            //利用反射获取字段
            Field[] fields = Build.class.getDeclaredFields();
            try {
                for (Field field : fields) {
                    field.setAccessible(true);
                    String name = field.getName();//获取字段名
                    String value = field.get(null).toString();//获取值

                    stringBuffer.append(name + "=" + value);
                    stringBuffer.append("\n");
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return stringBuffer.toString();
        }
  • 还要对外提供一个获取异常信息文件的方法,用于再次启动应用的时候获取该文件并上传
        /**
         * 获取崩溃的文件
         *
         * @return
         */
        public File getCrashFile() {
            SharedPreferences sharedPreferences = mContext.getSharedPreferences("crash", Context.MODE_PRIVATE);
            String carshFileName = sharedPreferences.getString("CRASH_FILE_NAME", "");
            return new File(carshFileName);
        }
  • 在MainActivity启动的时候,拿到该文件直接上传服务器,我们这里没有服务器,就直接把信息打印出来
      if (crashFile.exists()){
                //如果文件存在,上传服务器 。。。
                Logger.d("上传到服务器");
                //读取出来
                try {
                    FileReader fileReader = new FileReader(crashFile);
                    int len = 0;

                    char[] buf = new char[1024];
                    while ((len = fileReader.read(buf)) != -1){
                        //继续读
                        String crashInfo = new String(buf, 0, len);
                        Logger.d(crashInfo);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
  • 写完之后可以在应用的任何地方写一个异常试一试,第一次点击挂掉,然后再点一次就可以拿到崩溃信息了。

源码在这里

总结: 这样当应用崩溃的时候开发人员就可以及时的获取崩溃信息,针对性的修复bug,做热修复等等。当然bug监控也有很好的第三方平台,友盟和腾讯的Bugly都不错。可以自己选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_kayce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值