**Android 全局 异常捕捉**

这篇博客详细介绍了如何在Android应用中实现全局异常捕获,通过创建自定义的CrashHandlerUtils类,实现UncaughtExceptionHandler接口,来捕获并处理应用中的未捕获异常。当异常发生时,不仅收集设备信息和异常堆栈信息,还将其保存到本地文件,并可选择重启应用。同时,博客还展示了如何将异常信息上传到服务器进行分析。
摘要由CSDN通过智能技术生成

Android 全局 异常捕捉

1 在application中
1 主要类//本地异常记录
​​​
public class CrashHandlerUtils implements UncaughtExceptionHandler {
private static final String TAG = “CrashHandler”;
private UncaughtExceptionHandler mDefaultHandler;// 系统默认的UncaughtException处理类
private static CrashHandlerUtils INSTANCE = new CrashHandlerUtils();// CrashHandler实例
private Context mContext;// 程序的Context对象
private Map<String, String> info = new HashMap<String, String>();// 用来存储设备信息和异常信息
private SimpleDateFormat format = new SimpleDateFormat(
“yyyy-MM-dd-HH-mm-ss”);// 用于格式化日期,作为日志文件名的一部分

public static final int MSG_EMAIL = 0;
public static final int MSG_FILE = 1;
private int type;
private MyApplication myapplication;
/**
 * 是否自动重启
 */
private boolean reStart = false;

/**
 * 保证只有一个CrashHandler实例
 */
private CrashHandlerUtils() {

}

/**
 * 获取CrashHandler实例 ,单例模式
 */
public static CrashHandlerUtils getInstance() {
    return INSTANCE;
}


public boolean isReStart() {
    return reStart;
}

public void setReStart(boolean reStart) {
    this.reStart = reStart;
}

/**
 * 设置该CrashHandler为程序的默认处理器
 */
public void init(Context context, int type) {
    this.type = type;
    mContext = context;
    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器
    Thread.setDefaultUncaughtExceptionHandler(this);// 设置该CrashHandler为程序的默认处理器
}

/**
 * 重写@:当UncaughtException发生时会转入该重写的方法来处理
 */
@Override
public void uncaughtException(Thread thread, Throwable ex) {

    if (!handleException(ex) && mDefaultHandler != null) {
        // 如果自定义的没有处理则让系统默认的异常处理器来处理
        mDefaultHandler.uncaughtException(thread, ex);
    } else {

// try {
// Thread.sleep(3000);// 如果处理了,让程序继续运行3秒再退出,保证文件保存并上传到服务器
// restartApp();
// } catch (Exception e) {
// restartApp();
// e.printStackTrace();
// }
}
}

public void restartApp() {
    AlarmManager mgr = (AlarmManager) mContext.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(mContext.getApplicationContext(), MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    intent.putExtra("crash", true);
    PendingIntent restartIntent = PendingIntent.getActivity(mContext.getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 8000, restartIntent); //秒钟后重启应用

    android.os.Process.killProcess(android.os.Process.myPid());
    System.exit(0);
    System.gc();
}

/**
 * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
 *
 * @param ex 异常信息
 * @return true 如果处理了该异常信息;否则返回false.
 */
public boolean handleException(Throwable ex) {
    if (ex == null) {
        return false;
    }

// new Thread() {
// public void run() {
// Looper.prepare();
// Toast.makeText(mContext, “程序即将重启”, Toast.LENGTH_SHORT).show();
// Looper.loop();
// }
// }.start();
// 收集设备参数信息
collectDeviceInfo(mContext, info);
// 保存日志文件
saveCrashInfo2File(ex);
return true;
}

/**
 * 收集设备参数信息
 *
 * @param context
 */
public static void collectDeviceInfo(Context context,
                                     Map<String, String> info) {
    try {
        PackageManager pm = context.getPackageManager();// 获得包管理器
        PackageInfo pi = pm.getPackageInfo(context.getPackageName(),
                PackageManager.GET_ACTIVITIES);// 得到该应用的信息,即主Activity
        if (pi != null) {
            String versionName = pi.versionName == null ? "null"
                    : pi.versionName;
            String versionCode = pi.versionCode + "";
            info.put("versionName", versionName);
            info.put("versionCode", versionCode);
        }
    } catch (NameNotFoundException e) {
        e.printStackTrace();
    }

    Field[] fields = Build.class.getDeclaredFields();// 反射机制
    for (Field field : fields) {
        try {
            field.setAccessible(true);
            info.put(field.getName(), field.get("").toString());

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 把錯誤信息保存本地。
 *
 * @param ex
 * @return
 */
private String saveCrashInfo2File(Throwable ex) {
    StringBuffer sb = new StringBuffer();
    for (Map.Entry<String, String> entry : info.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        sb.append(key + "=" + value + "\r\n");
    }
    Writer writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    ex.printStackTrace(pw);
    Throwable cause = ex.getCause();
    // 循环着把所有的异常信息写入writer中
    while (cause != null) {
        cause.printStackTrace(pw);
        cause = cause.getCause();
    }
    pw.close();// 记得关闭
    String result = writer.toString();
    UploadException(result,sb.toString(),ex.toString());

    sb.append(result);
   LUtils.e("System.out", "错误信息:" + sb.toString());
    // 保存文件
    long timetamp = System.currentTimeMillis();
    String time = format.format(new Date());
    String fileName = "crash-" + time + "-" + timetamp + ".log";
    if (Environment.getExternalStorageState().equals(
            Environment.MEDIA_MOUNTED)) {
        try {
            File dir = new File(Environment.getExternalStorageDirectory()
                    .getAbsolutePath() + File.separator + "ErrorInfo");

            LUtils.i("CrashHandler", dir.toString());
            if (!dir.exists()) {
                dir.mkdir();
            } else {
                if (dir.isDirectory()) {
                    File[] files = dir.listFiles();
                    if (files != null) {
                        if (files.length > 300) {
                            List<File> list = new ArrayList<>();

                            try {
                                for (int x = 0, len = files.length; x < len; x++) {
                                    File file = files[x];
                                    list.add(file);
                                }

                                Collections.sort(list, new Comparator<File>() {
                                    @Override
                                    public int compare(File file, File file1) {
                                        return file.getName().compareTo(file1.getName());
                                    }

                                    @Override
                                    public boolean equals(Object o) {
                                        return false;
                                    }
                                });
                                for (int x = 0, len = list.size(); x < len && x < len - 300; x++) {
                                    File file = list.get(x);
                                    file.delete();
                                }

// String atr3 = “暗示法撒地方”;
} catch (NumberFormatException e) {
LUtils.e(TAG, "saveCrashInfo2File: "+ e);
}
}
}
}
}

            FileOutputStream fos = new FileOutputStream(new File(dir,
                    fileName));
            fos.write(sb.toString().getBytes());
            fos.close();

            return fileName;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

private void UploadException(String stack,String env, String title) {
    UmKernel.getInstance().runCachedThread(new Runnable() {
        @Override
        public void run() {
            ExceptionBean exceptionBean= new ExceptionBean();
            exceptionBean.setTitle(title);
            exceptionBean.setStack(stack);
            exceptionBean.setEnv(env);
            exceptionBean.setPlatform("android");
            exceptionBean.setRemark("fwf");
            exceptionBean.setClient(SystemToolUtils.getLocalIpDisplayAddress());
            Call<ExceptionBean> exceptionBeanCall =
                    HttpHelper.getCommonApiUrl().uploadException(exceptionBean);
            exceptionBeanCall.enqueue(new Callback<ExceptionBean>() {
                @Override
                public void onResponse(Call<ExceptionBean> call, Response<ExceptionBean> response) {
                    if (response != null) {

                    }
                }

                @Override
                public void onFailure(Call<ExceptionBean> call, Throwable t) {

                }
            });

        }
    });

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值