一:为什么要处理?

其实我们都知道,在开发过程中,自己的app系统或许有许多隐藏的异常,自己没有捕捉到,那么关于异常的捕捉,这是相当重要的,如果系统发生崩溃,那么至少也可以让系统挂在系统之内,不会发现什么系统直接退了,或者是卡死,这样做,能够使得用户体验效果更加,自己也可以发现用户到底出现什么异常,便于自己以后好处理这个问题,优化处理自己的系统。

二:如何解决

在Android 开发中,自身其实带有一个系统默认的异常处理接口,UncaughtExceptionHandler,该接口呢,能够很好的处理程序中发生的异常,所以,往往开发者都喜欢使用它,而且它也是一个非常简单好用的东西。

三:具体实现

(1)实现UncaughtExceptionHandler接口的类

package com.x1.tools;  

import java.lang.Thread.UncaughtExceptionHandler;  

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.os.Looper;
import android.util.Log; import com.x1.dao.SubmitConfigBugs;
import com.x1.ui.R; /**
* 未捕获异常捕捉类
*
* @author zengtao 2015年5月6日
*
*
*/
public class CrashHandlers implements UncaughtExceptionHandler { public static final String TGA = "CrashHandlers"; // 系统默认的UncaughtException处理类
private Thread.UncaughtExceptionHandler mDefaultHandler; // CrashHandler实例
private static CrashHandlers instance;
// 程序的Context对象
private Context mContext; private GetPhoneInfo phone; /** 保证只有一个CrashHandler实例 */
private CrashHandlers() {
} /** 获取CrashHandler实例 ,单例模式 */
public synchronized static CrashHandlers getInstance() {
if (instance == null) {
instance = new CrashHandlers();
}
return instance;
} /**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
// 获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
phone = new GetPhoneInfo(context);
} /**
* 当UncaughtException发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(thread, ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TGA, e.toString());
}
// 退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
} /**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Thread thread, Throwable ex) {
if (ex == null) {
return false;
}
// 使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
ShowToast.show(mContext, "喵,很抱歉,程序出现异常,即将退出!",
R.drawable.error_icon);
Looper.loop();
}
}.start();
// 把异常信息和设备信息上传到服务器
subMitThreadAndDeviceInfo(mContext, thread, ex);
return true;
} // 提交信息到服务器
public void subMitThreadAndDeviceInfo(Context ctx, Thread thread,
Throwable ex) {
// 当前用户的账号
String Account = null;
if (Config.getCachedAccount(ctx) != null) {
Account = Config.getCachedAccount(ctx);
} else {
Account = "当前无用户登录";
}
// 手机设备的信息
String PhoneModel = phone.PhoneModel;
String PhoneVersion = phone.PhoneVersion;
String PhoneResolution = phone.PhoneResolution;
String ZcmVersion = phone.ZcmVersion;
String AvailableRom = phone.AvailableRom;
// 获取当前显示在界面上的Activity的路径加类名
ActivityManager am = (ActivityManager) ctx
.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
// 异常信息加异常所在类的绝对路径
final String content = "thread: " + thread + " , name: "
+ thread.getName() + ", id: " + thread.getId()
+ ", exception: " + ex + ", " + cn.getClassName(); // 执行接口,把异常信息提交到服务器
new SubmitConfigBugs(0, ctx, Account, PhoneModel, PhoneVersion,
PhoneResolution, ZcmVersion, AvailableRom, content,
new SubmitConfigBugs.SuccessCallback() {
@Override
public void onSuccess() {
Log.e(TGA, content + "\n错误信息提交成功");
}
}, new SubmitConfigBugs.FailCallback() { @Override
public void onFail() {
Log.e(TGA, content + "\n错误信息提交失败");
}
});
} }

(2)实体类:手机信息

package com.x1.tools;  

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import android.view.Display;
import android.view.WindowManager; /**
* 获取当前手机的设备信息和当前软件的版本
*
* @author zengtao 2015年5月6日
*
*
*/
public class GetPhoneInfo {
private Context context;
public String PhoneModel;
public String PhoneVersion;
public String PhoneResolution;
public String ZcmVersion;
public String AvailableRom; public GetPhoneInfo(Context context) {
this.context = context;
PhoneModel = android.os.Build.MODEL;
PhoneVersion = android.os.Build.VERSION.RELEASE;
PhoneResolution = getDisplayWAndH();
ZcmVersion = getAppVersionName(this.context);
AvailableRom = "ROM剩余存储空间: " + getAvailableInternalMemorySize() + "MB"
+ ",内置SDCard剩余存储空间: " + getAvailableExternalMemorySize() + "MB";
} // 获取当前版本号
private String getAppVersionName(Context context) {
String versionName = "";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
"com.x1.ui", 0);
versionName = packageInfo.versionName;
if (TextUtils.isEmpty(versionName)) {
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return versionName;
} // 获取屏幕分辨率
@SuppressWarnings("deprecation")
private String getDisplayWAndH() {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
String string = "屏幕分辨率: " + display.getWidth() + "x"
+ display.getHeight();
return string;
} /**
*
* @return ROM存储路径
*/
private String getInternalMemoryPath() {
return Environment.getDataDirectory().getPath();
} /**
*
* @return 内置sd卡路径
*/
private String getExternalMemoryPath() {
return Environment.getExternalStorageDirectory().getPath();
} /**
*
* @param path
* 文件路径
* @return 文件路径的StatFs对象
* @throws Exception
* 路径为空或非法异常抛出
*/
private StatFs getStatFs(String path) {
try {
return new StatFs(path);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
*
* @param stat
* 文件StatFs对象
* @return 剩余存储空间的MB数
*
*/
@SuppressWarnings("deprecation")
private float calculateSizeInMB(StatFs stat) {
if (stat != null)
return stat.getAvailableBlocks()
* (stat.getBlockSize() / (1024f * 1024f));
return 0.0f;
} /**
*
* @return ROM剩余存储空间的MB数
*/
private float getAvailableInternalMemorySize() { String path = getInternalMemoryPath();// 获取数据目录
StatFs stat = getStatFs(path);
return calculateSizeInMB(stat);
} /**
*
* @return 内置SDCard剩余存储空间MB数
*/
private float getAvailableExternalMemorySize() { String path = getExternalMemoryPath();// 获取数据目录
StatFs stat = getStatFs(path);
return calculateSizeInMB(stat); }
}

  

  1. package com.x1.tools;
  2. import java.lang.Thread.UncaughtExceptionHandler;
  3. import android.app.ActivityManager;
  4. import android.content.ComponentName;
  5. import android.content.Context;
  6. import android.os.Looper;
  7. import android.util.Log;
  8. import com.x1.dao.SubmitConfigBugs;
  9. import com.x1.ui.R;
  10. /**
  11. * 未捕获异常捕捉类
  12. *
  13. * @author zengtao 2015年5月6日
  14. *
  15. *
  16. */
  17. public class CrashHandlers implements UncaughtExceptionHandler {
  18. public static final String TGA = "CrashHandlers";
  19. // 系统默认的UncaughtException处理类
  20. private Thread.UncaughtExceptionHandler mDefaultHandler;
  21. // CrashHandler实例
  22. private static CrashHandlers instance;
  23. // 程序的Context对象
  24. private Context mContext;
  25. private GetPhoneInfo phone;
  26. /** 保证只有一个CrashHandler实例 */
  27. private CrashHandlers() {
  28. }
  29. /** 获取CrashHandler实例 ,单例模式 */
  30. public synchronized static CrashHandlers getInstance() {
  31. if (instance == null) {
  32. instance = new CrashHandlers();
  33. }
  34. return instance;
  35. }
  36. /**
  37. * 初始化
  38. *
  39. * @param context
  40. */
  41. public void init(Context context) {
  42. mContext = context;
  43. // 获取系统默认的UncaughtException处理器
  44. mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
  45. // 设置该CrashHandler为程序的默认处理器
  46. Thread.setDefaultUncaughtExceptionHandler(this);
  47. phone = new GetPhoneInfo(context);
  48. }
  49. /**
  50. * 当UncaughtException发生时会转入该函数来处理
  51. */
  52. @Override
  53. public void uncaughtException(Thread thread, Throwable ex) {
  54. if (!handleException(thread, ex) && mDefaultHandler != null) {
  55. // 如果用户没有处理则让系统默认的异常处理器来处理
  56. mDefaultHandler.uncaughtException(thread, ex);
  57. } else {
  58. try {
  59. Thread.sleep(3000);
  60. } catch (InterruptedException e) {
  61. Log.e(TGA, e.toString());
  62. }
  63. // 退出程序
  64. android.os.Process.killProcess(android.os.Process.myPid());
  65. System.exit(1);
  66. }
  67. }
  68. /**
  69. * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
  70. *
  71. * @param ex
  72. * @return true:如果处理了该异常信息;否则返回false.
  73. */
  74. private boolean handleException(Thread thread, Throwable ex) {
  75. if (ex == null) {
  76. return false;
  77. }
  78. // 使用Toast来显示异常信息
  79. new Thread() {
  80. @Override
  81. public void run() {
  82. Looper.prepare();
  83. ShowToast.show(mContext, "喵,很抱歉,程序出现异常,即将退出!",
  84. R.drawable.error_icon);
  85. Looper.loop();
  86. }
  87. }.start();
  88. // 把异常信息和设备信息上传到服务器
  89. subMitThreadAndDeviceInfo(mContext, thread, ex);
  90. return true;
  91. }
  92. // 提交信息到服务器
  93. public void subMitThreadAndDeviceInfo(Context ctx, Thread thread,
  94. Throwable ex) {
  95. // 当前用户的账号
  96. String Account = null;
  97. if (Config.getCachedAccount(ctx) != null) {
  98. Account = Config.getCachedAccount(ctx);
  99. } else {
  100. Account = "当前无用户登录";
  101. }
  102. // 手机设备的信息
  103. String PhoneModel = phone.PhoneModel;
  104. String PhoneVersion = phone.PhoneVersion;
  105. String PhoneResolution = phone.PhoneResolution;
  106. String ZcmVersion = phone.ZcmVersion;
  107. String AvailableRom = phone.AvailableRom;
  108. // 获取当前显示在界面上的Activity的路径加类名
  109. ActivityManager am = (ActivityManager) ctx
  110. .getSystemService(Context.ACTIVITY_SERVICE);
  111. ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
  112. // 异常信息加异常所在类的绝对路径
  113. final String content = "thread: " + thread + " , name: "
  114. + thread.getName() + ", id: " + thread.getId()
  115. + ", exception: " + ex + ", " + cn.getClassName();
  116. // 执行接口,把异常信息提交到服务器
  117. new SubmitConfigBugs(0, ctx, Account, PhoneModel, PhoneVersion,
  118. PhoneResolution, ZcmVersion, AvailableRom, content,
  119. new SubmitConfigBugs.SuccessCallback() {
  120. @Override
  121. public void onSuccess() {
  122. Log.e(TGA, content + "\n错误信息提交成功");
  123. }
  124. }, new SubmitConfigBugs.FailCallback() {
  125. @Override
  126. public void onFail() {
  127. Log.e(TGA, content + "\n错误信息提交失败");
  128. }
  129. });
  130. }
  131. }

Android 捕捉app系统中未处理的异常的更多相关文章

  1. Android实现app长时间未操作时自动退出app

    这里要考虑3个问题,第一个是锁屏问题,第二个是app被切换至后台的问题,第三个是屏幕锁定和解除时app在后台时的问题 一,监听屏幕解锁,锁定 ? 1 2 3 4 5 6 7 8 9 10 11 12 ...

  2. C# 截获某个域中未捕获的异常 CLR20R3 程序终止的几种解决方案

    AppDomain.UnhandledException可以获的异常,却截不下来,求解 AppDomain.CurrentDomain.UnhandledException += CurrentDom ...

  3. Android应用图标微技巧,8.0系统中应用图标的适配

    现在已经进入了2018年,Android 8.0系统也逐渐开始普及起来了.三星今年推出的最新旗舰机Galaxy S9已经搭载了Android 8.0系统,紧接着小米.华为.OV等国产手机厂商即将推出的 ...

  4. Android 8.0系统的应用图标适配

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 参考资料<一起来学习Android 8.0系统的应用图标适配吧>中已经讲得很清楚了,这里我只是简单总结下.详情的内容请阅 ...

  5. Android中使用UncaughtExceptionHandler来处理未捕获的异常

    原文在sparkyuan.me上.转载注明出处:http://sparkyuan.github.io/2016/03/28/使用UncaughtExceptionHandler来处理未捕获的异常/ 全 ...

  6. app测试中,ios和android的区别

    App测试中ios和Android的区别: 1. Android长按home键呼出应用列表和切换应用,然后右滑则终止应用: 2. 多分辨率测试,Android端20多种,ios较少: 3. 手机操作系 ...

  7. Android App在Google App Store中搜不到

    情景:Android App在Google App Store上架成功,三星手机可以在Google App Store中搜索到,但是三星tablet却无法在Google App Store中搜索到,目 ...

  8. Android系统中自定义按键的短按、双击、长按事件

    在项目中碰到这样的问题: 由于系统中的按键在底层做了重新定义或者新增了按键,此时需要在APP层对按键事件(keyevent)做分解处理,模拟Android系统做法,把keyevent分解成: 1.单击 ...

  9. [原创]Android系统中常用JAVA类源码浅析之HashMap

    由于是浅析,所以我只分析常用的接口,注意是Android系统中的JAVA类,可能和JDK的源码有区别. 首先从构造函数开始, /** * Min capacity (other than zero) ...

随机推荐

  1. POJ 1182 食物链(经典并查集) (多组输入有时乱加也会错!)

      多组输入有时乱加也会错! 这次用多组输入竟然,不用竟然对了,所以以后做题目,若是答案错误,先看加上或者删掉多组输入,看对不对 食物链 Time Limit: 1000MS   Memory Lim ...

  2. CSU 1809 Parenthesis 思维+线段树

    1809: Parenthesis Submit Page     Summary    Time Limit: 5 Sec     Memory Limit: 128 Mb     Submitte ...

  3. yzoj P2344 斯卡布罗集市 题解

    共t条街对于每一条街上有n个店铺(n可能不相同),每次只能选两端第一个营业的店铺采购,采购第i个店铺会获得幸福度ai,采购完后,这个店铺和它相邻的店铺便会关门,问最大幸福度? 考场想了一下dp,一开始 ...

  4. Spring@Autowired java.lang.NullPointerException 空指针

    在使用@Autowired注解注入出现的空指针  java.lang.NullPointerException  可能存在的错误原因: 1.注解的扫描有问题 在xml配置了这个标签后,spring可以 ...

  5. Django系列---使用MySql数据库

    目录 1. 创建数据库 1.1. 使用utf8mb4编码 1.1.1. 确定mysql的配置文件 1.1.2. 修改配置文件 1.1.3. 重启数据库服务,检查相关字段 1.1.4. 新建数据库 1. ...

  6. JDBC进行批处理Batch

    在实际的项目开发中,有时候需要向数据库发送一批SQL语句执行,这时应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率. JDBC实现批处理有两种方式:statement和pr ...

  7. Node.js+Navicat for MySQL实现的简单增删查改

    前提准备: 电脑上必须装有服务器环境,Navicat for MySQL(我用的是这款MySQL,可随意),Node环境 效果如图所示: 源码地址: GitHub:https://github.com ...

  8. 通过Service访问应用 (2)

    目录 通过NodePort Service在外部访问集群应用 通过LoadBalancer Service在外部访问集群应用 Microsoft SQL Server数据库部署 为了便于理解和学习,请 ...

  9. 常用 JS 函数

    各种业务开发都离不开对数据的处理,然而遇到的很多数据都是不好处理的.这个时候就需要寻求搜索引擎的帮助.这种方法效率是非常低下的,而且根据作者的个性不能保证其对自己的口味.因此这篇文字包含了一份 JS ...

  10. 第一次参与国际空间站ISS 的SSTV活动

    先来看看本次 ISS 的 SSTV活动公告 SSTV Event planned for Early August ARISS News Release                         ...