Android开发之全局异常捕获


[转载请注明出处]本文出自付小华的博客 http://blog.csdn.net/klxh2009

今晨谷歌正式发布Android 8.0,新版本的Android O系统对API做出了各种变更,其中大部分会影响到很多应用,其中包括记录未捕获的异常.
如果某个应用安装的Thread.UncaughtExceptionHandler未移交给默认的Thread.UncaughtExceptionHandler,则当出现未捕获的异常时,系统不会终止应用,即不会出现系统默认的抱歉,xxx应用已停止运行”.因此,我们就可以对应用的异常进行全局捕获,从而将异常保存下来,方便以后分析问题.

接下来查看源码:


通过源码可以知道:
Thread.UncaughtExceptionHandler是一个当线程由于未捕获的异常突然终止而调用处理程序的接口.
当线程由于未捕获的异常即将终止时,Java虚拟机将使用它来查询其UncaughtExceptionHandler的线程Thread.getUncaughtExceptionHandler(),并将调用处理程序的 uncaughtException方法,将线程和异常作为参数传递。如果一个线程没有显示它的UncaughtExceptionHandler,那么它的ThreadGroup对象充当它的 UncaughtExceptionHandler。如果ThreadGroup对象没有处理异常的特殊要求,它可以将调用转发到默认的未捕获的异常处理程序。

因此我们可以自定一个类去实现该接口,该类主要用于收集错误信息和保存错误信息.

详细代码

/*** 作用:* 1.收集错误信息* 2.保存错误信息* Created by shenhua on 2017-08-22-0022.* Email shenhuanet@126.com*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {private static CrashHandler sInstance = null;private Thread.UncaughtExceptionHandler mDefaultHandler;private Context mContext;// 保存手机信息和异常信息private Map<String, String> mMessage = new HashMap<>();public static CrashHandler getInstance() {if (sInstance == null) {synchronized (CrashHandler.class) {if (sInstance == null) {synchronized (CrashHandler.class) {sInstance = new CrashHandler();}}}}return sInstance;}private CrashHandler() {}/*** 初始化默认异常捕获** @param context context*/public void init(Context context) {mContext = context;// 获取默认异常处理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 将此类设为默认异常处理器Thread.setDefaultUncaughtExceptionHandler(this);}@Overridepublic void uncaughtException(Thread t, Throwable e) {if (!handleException(e)) {// 未经过人为处理,则调用系统默认处理异常,弹出系统强制关闭的对话框if (mDefaultHandler != null) {mDefaultHandler.uncaughtException(t, e);}} else {// 已经人为处理,系统自己退出try {Thread.sleep(1000);} catch (InterruptedException e1) {e1.printStackTrace();}Process.killProcess(Process.myPid());System.exit(1);}}/*** 是否人为捕获异常** @param e Throwable* @return true:已处理 false:未处理*/private boolean handleException(Throwable e) {if (e == null) {// 异常是否为空return false;}new Thread() {// 在主线程中弹出提示@Overridepublic void run() {Looper.prepare();Toast.makeText(mContext, "捕获到异常", Toast.LENGTH_SHORT).show();Looper.loop();}}.start();collectErrorMessages();saveErrorMessages(e);return false;}/*** 1.收集错误信息*/private void collectErrorMessages() {PackageManager pm = mContext.getPackageManager();try {PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);if (pi != null) {String versionName = TextUtils.isEmpty(pi.versionName) ? "null" : pi.versionName;String versionCode = "" + pi.versionCode;mMessage.put("versionName", versionName);mMessage.put("versionCode", versionCode);}// 通过反射拿到错误信息Field[] fields = Build.class.getFields();if (fields != null && fields.length > 0) {for (Field field : fields) {field.setAccessible(true);try {mMessage.put(field.getName(), field.get(null).toString());} catch (IllegalAccessException e) {e.printStackTrace();}}}} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();}}/*** 2.保存错误信息** @param e Throwable*/private void saveErrorMessages(Throwable e) {StringBuilder sb = new StringBuilder();for (Map.Entry<String, String> entry : mMessage.entrySet()) {String key = entry.getKey();String value = entry.getValue();sb.append(key).append("=").append(value).append("\n");}Writer writer = new StringWriter();PrintWriter pw = new PrintWriter(writer);e.printStackTrace(pw);Throwable cause = e.getCause();// 循环取出Causewhile (cause != null) {cause.printStackTrace(pw);cause = e.getCause();}pw.close();String result = writer.toString();sb.append(result);String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date());String fileName = "crash-" + time + "-" + System.currentTimeMillis() + ".log";// 有无SD卡if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {String path = Environment.getExternalStorageDirectory().getPath() + "crash/";File dir = new File(path);if (!dir.exists()) dir.mkdirs();FileOutputStream fos = null;try {fos = new FileOutputStream(path + fileName);fos.write(sb.toString().getBytes());} catch (Exception e1) {e1.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e1) {e1.printStackTrace();}}}}}
}

CrashHandler注释比较清晰,应该可以看得明白.

使用

public class App extends Application {@Overridepublic void onCreate() {super.onCreate();CrashHandler.getInstance().init(this);}
}

注意事项

  • 6.0运行时权限请求
  • Application全局设定

Android开发之全局异常捕获相关推荐

  1. Android全局异常捕获

    Android全局异常捕获 参考文章: (1)Android全局异常捕获 (2)https://www.cnblogs.com/heweiquan/p/10973201.html 备忘一下.

  2. Spring 全局异常捕获

    引言 前后端分离开发,后台有时候会出现不可预知的异常(运行时异常),在实际生产中通常需要统一返回符合一定响应结构的异常信息给前端,这一方面可以避免用户看到后台的报错信息,一方面也是保护后端程序免受恶意 ...

  3. 《全局异常捕获》劝劝潘子吧,别再用trycatch来处理异常了

    人世仙家本自殊,何须相见向中途.惊鸿瞥过游龙去,漫恼陈王一事无. 嗨,大家好,我是洛神,性别男.一个来自快乐星球的程序员. 欢迎大家专注我的公众号[程序员洛神],不仅分享技术,还会分享生活趣事.体育. ...

  4. 编码技巧——全局异常捕获统一的返回体业务异常

    在开发中,关于异常的捕获曾经是一个头疼的问题:本篇介绍几个方法,如何优雅的捕获处理业务异常: 已检查异常和未检查异常? 先做个介绍,异常Exception分为运行时异常(RuntimeExceptio ...

  5. SpringBoot框架搭建(redis多数据源+数据库多数据源+全局异常捕获)

    java骨架 目录结构 ├── mvnw ├── mvnw.cmd ├── pom.xml ├── README.md ├── src/ 源文件目录 │ ├── main │ │ ├── java │ ...

  6. Spring boot异常统一处理方法:@ControllerAdvice注解的使用、全局异常捕获、自定义异常捕获

    Spring boot异常统一处理方法:@ControllerAdvice注解的使用.全局异常捕获.自定义异常捕获 参考文章: (1)Spring boot异常统一处理方法:@ControllerAd ...

  7. atitit.js浏览器环境下的全局异常捕获

    atitit.js浏览器环境下的全局异常捕获 window.onerror = function(errorMessage, scriptURI, lineNumber) { var s= JSON. ...

  8. spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获

    spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获 当你的某个控制器内的某个方法报错,基本上回显示出java错误代码,非常不友好,这 ...

  9. 捕获异常_SpringBoot的异常处理全局异常捕获(图文资料)

    目标:springboot全局异常捕获 概述 1.自定义异常处理 package com.itheima.exeception; /** * @Author David老师 * @Descriptio ...

最新文章

  1. 2022-2028年中国边缘计算行业投资分析及前景预测报告(全卷)
  2. 大华管理平台用户名_大华HOC智慧物流可视化联网追溯解决方案,助力物流行业更高效...
  3. python创_Python创建Windows 服务
  4. scp命令:服务器间远程复制代码
  5. Java同步锁——lock与synchronized 的区别【转】
  6. *【CodeForces - 1088 ABC】套题比赛,A水题B模拟C构造D交互
  7. 世界一流大学的计算机专业,在用哪些书当教材?
  8. ASP.NET 2.0 - 如何于网页上新增包括图片在内的数据至数据库
  9. php简单登陆,PHP简单实现单点登录
  10. 浅谈Java两种并发类型——计算密集型与IO密集型
  11. C语言程序——如何是使用TurboC2编程调试
  12. Windows远程桌面使用本地USB打印机
  13. N元语言模型的训练方法
  14. 微电影后期制作的流程
  15. python wgs84坐标转换_python WGS84和ECEF坐标的转换
  16. Flink基础系列8-Flink on yarn运行wordcount程序
  17. QQ空间签到说说表情代码大全
  18. 【JavaScript】VUE前端实现微信版录制音频wav格式转化成mp3格式和Base64
  19. 云管理平台的安全措施
  20. iOS 9公测开启 智能预测/省电模式亮相

热门文章

  1. Toward Fast, Flexible, and Robust Low-Light Image Enhancement(实现快速、灵活和稳健的弱光图像增强)CVPR2022
  2. 举个栗子!Tableau 技巧(175):通过 URL 传参实现不同工作簿的跳转
  3. 内核编译出错 [arch/arm/boot/compressed/piggy.lzo] Error 1
  4. html5如何实现无序排列,无序列表让li横排
  5. TBR:AWS不是云计算领导者,Microsoft才是
  6. http请求报文 主机IP_计算机网络基础:这是一份详细HTTP学习指南
  7. H5监听摇一摇和手机倾斜事件(重力感应)
  8. 粒子群算法python(含例程代码与详解)
  9. 计算机导论基础论文3000字,计算机导论课论文3000字
  10. u盘启动工具哪个好用