Android 捕捉app系统中未处理的异常
Posted 荣耀王者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 捕捉app系统中未处理的异常相关的知识,希望对你有一定的参考价值。
一:为什么要处理?
其实我们都知道,在开发过程中,自己的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); } }
- 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错误信息提交失败");
- }
- });
- }
- }
以上是关于Android 捕捉app系统中未处理的异常的主要内容,如果未能解决你的问题,请参考以下文章