Android app如果出现了崩溃现象,系统的“程序异常退出”,给应用的用户体验造成不良影响。为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理。
(当然你也可以用友盟,不仅可以帮你记录异常日志,还可以帮你做很多统计信息)
开发者就可以及时获取在该设备上导致崩溃的信息,这对于下一个版本的bug修复帮助极大,所以今天就来介绍一下“游戏蜂窝”如何在程序崩溃的情况下收集相关的设备参数信息和具体的异常信息,并发送这些信息到服务器供开发者分析和调试程序。
Thread.UncaughtExceptionHandler:线程未捕获异常处理器,用来处理未捕获异常。如果程序出现了未捕获异常,默认会弹出系统中强制关闭对话框。我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可以做一些个性化的异常处理操作。
![](/assets/blank.gif)
下面是“游戏蜂窝”的异常处理类
package com.cyjh.gundam.application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Process;
import android.util.Log;
import com.umeng.message.MsgConstant;
import com.umeng.socialize.common.SocializeConstants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class CrashHandler implements UncaughtExceptionHandler {
private static CrashHandler INSTANCE = new CrashHandler();CrashHandler实例
public static final String TAG = "CrashHandler";
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");//用于格式化日期,作为日志文件名的一部分
private Map<String, String> infos = new HashMap();//用来存储设备信息和异常信息
private Context mContext;//程序的Context对象
private UncaughtExceptionHandler mDefaultHandler; //系统默认的UncaughtException处理类
/** 保证只有一个CrashHandler实例 */
private CrashHandler() {
}
/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
return INSTANCE;
}
//初始化
public void init(Context context) {
this.mContext = context;
//获取系统默认的UncaughtException处理器
this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
}
//当UncaughtException发生时会转入该函数来处理
public void uncaughtException(Thread thread, Throwable ex) {
if (handleException(ex) || this.mDefaultHandler == null) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
Log.e(TAG, "error : ", e);
}
//退出程序
Process.killProcess(Process.myPid());
System.exit(1);
} else {
this.mDefaultHandler.uncaughtException(thread, ex);
}
ex.printStackTrace();
}
//自定义错误处理,收集错误信息 发送错误报告等操作均在此完成
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
//使用1类(其实就是CrashHandler$1 内部类)线程来显示异常信息 (普通做法是使用Toast来显示异常信息)
new 1(this).start(); //
collectDeviceInfo(this.mContext); //手机设备信息
saveCrashInfo2File(ex); //保存异常信息到文件
ex.printStackTrace();
return true;
}
//手机设备信息方法
public void collectDeviceInfo(Context ctx) {
try {
PackageInfo pi = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 1);
if (pi != null) {
String versionCode = pi.versionCode + "";
this.infos.put("versionName", pi.versionName == null ? "null" : pi.versionName);
this.infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "an error occured when collect package info", e);
}
for (Field field : Build.class.getDeclaredFields()) {
try {
field.setAccessible(true);
this.infos.put(field.getName(), field.get(null).toString());
Log.d(TAG, field.getName() + " : " + field.get(null));
} catch (Exception e2) {
e2.printStackTrace();
Log.e(TAG, "an error occured when collect crash info", e2);
}
}
}
//保存异常信息到文件方法
private String saveCrashInfo2File(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Entry<String, String> entry : this.infos.entrySet()) {
String value = (String) entry.getValue();
sb.append(((String) entry.getKey()) + "=" + value + "\n");
}
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
for (Throwable cause = ex.getCause(); cause != null; cause = cause.getCause()) {
cause.printStackTrace(printWriter);
}
printWriter.close();
sb.append(writer.toString());
try {
String fileName = "crash-" + this.formatter.format(new Date()) + SocializeConstants.OP_DIVIDER_MINUS + System.currentTimeMillis() + MsgConstant.CACHE_LOG_FILE_EXT;
String path = BaseApplication.getInstance().getErrorLogPath(this.mContext, fileName);
System.out.println("错误日志保存路径:=" + path);
File dir = new File(path);
if (!dir.exists()) {
dir.createNewFile();
}
FileOutputStream fos = new FileOutputStream(path);
fos.write(sb.toString().getBytes());
fos.close();
return fileName;
} catch (Exception e) {
Log.e(TAG, "an error occured while writing file...", e);
return null;
}
}
}
CrashHandler$1类代码
![](/assets/blank.gif)
看完这个CrashHandler后,我们知道要在一个Application环境中让其运行,需要在自定义的application中注册,我们继承android.app.Application,添加如下的代码
![](/assets/blank.gif)
那么我也看看“游戏蜂窝式如何处理的。在jadx 工具中我们选择"CrashHandler"类右键菜单中选择“FindUsage”很快就可以发现在“游戏蜂窝”中异常处理类的注册代码是:
CrashHandler.getInstance().init(getInstance());
网络搜索一下“UncaughtExceptionHandler”,应征了一句话。只要你输入关键字对,会有你要的代码。不信你看网络上代码几乎完全一样。
Android使用UncaughtExceptionHandler捕获全局异常
http://blog.csdn.net/lsw305264677/article/details/51308770
游戏蜂窝研究--全局的异常捕获器相关推荐
- 《SpringBoot从菜鸟到老鸟》之SpringBoot 如何配置全局的异常捕获
SpringBoot 如何配置全局的异常捕获 SpringBoot中自带的异常捕获机制返回的默认页面比较丑,对用户来说不够人性化. 所以这篇文章来讲解SpringBoot钟自定义全局异常捕获. 主要讲 ...
- SpringBoot配置全局的异常捕获
需要以下两个类配合完成: IoExceptionHandler.java(异常助手类) IMoocJSONResult.java(实体类) package com.blog.pojo;import o ...
- ajax invoke error,配置全局的异常捕获时,走ajax请求下面报错
org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet [dispatcherSe ...
- 编码技巧——全局异常捕获统一的返回体业务异常
在开发中,关于异常的捕获曾经是一个头疼的问题:本篇介绍几个方法,如何优雅的捕获处理业务异常: 已检查异常和未检查异常? 先做个介绍,异常Exception分为运行时异常(RuntimeExceptio ...
- Android 全局异常捕获DefaultUncaughtExceptionHandler与Cockroach
前言 Android中虽然可以通过设置 Thread.setDefaultUncaughtExceptionHandler来捕获全局的所有线程的异常,但主线程抛出异常时仍旧会导致activity闪退, ...
- Spring Boot配置全局异常捕获
1 SpringBoot配置全局的异常捕获 项目的说明 配置thymeleaf作为视图模板 ExceptionController.java模拟测试用 MyAjaxExceptionHandler.j ...
- springboot怎么返回404_深度分析:SpringBoot异常捕获与封装处理,看完你学会了吗?...
简介 日常开发过程中,难免有的程序会因为某些原因抛出异常,而这些异常一般都是利用try ,catch的方式处理异常或者throw,throws的方式抛出异常不管.这种方法对于程序员来说处理也比较麻烦, ...
- SpringBoot精通系列-如何封装Spring Boot异常捕获
导语 在Spring Boot开发过程中,不难避免的就是异常处理,有些异常是通过try catch方式捕获,或者是通过Throw直接抛出,但是这种方式的话对于客户端是不友好的,所以希望是通过编码的 ...
- spring框架做全局异常捕获_SpringBoot全局异常处理与定制404页面
一.错误处理原理分析 使用SpringBoot创建的web项目中,当我们请求的页面不存在(http状态码为404),或者器发生异常(http状态码一般为500)时,SpringBoot就会给我们返回错 ...
最新文章
- virtualbox+vagrant学习-2(command cli)-16-vagrant snapshot命令
- 美团悄悄进入企业早餐,其战略目的为高频带低频?
- LeetCode刷题记录(2)
- 淘宝客程序 —— 突破了传统淘宝客程序对自动采集商品收费的模式
- mvc移动创建oracle表,使用 ASP.NET MVC (C#)在15分钟内创建电影数据库应用程序 | Microsoft Docs...
- 擅长排列的小明(nyoj19)
- Flutter实战一Flutter聊天应用(九)
- 如何用B表的数据,更新A表的值
- 一个月的java工作总结
- Unity3D学习——使用PUN写一个聊天功能
- 支撑 100Gbit/s K8s 集群的未来网络数据平面
- MySQL必做练习题33道(员工信息,工资等级,部门信息)
- MySQL下载安装运行
- 【图解经典算法题】如何用一行代码解决约瑟夫环问题
- 刷题学习—算法思想(双指针、排序、回溯、二分法、滑动窗口、贪心、单调栈)
- 开发客户的渠道+方法
- 巅峰产生虚伪拥护,黄昏见证忠诚信徒
- 吉林大学软件学院——UMl作业3
- swift block语法
- JAVA实现简单的客户选购系统
热门文章
- 【论文翻译】Mask R-CNN
- ubuntu 使用Rythmbox收听国际音乐电台
- web前端开发七武器—Jasmine入门教程(上)
- 日撸leetCode三道题---Day1---二分查找
- 【数据分析可视化】各国商店-小试牛刀
- 2005是网游商最尴尬一年 涉赌投诉意外死亡
- 制作GIF神器(小于2MB,操作简单)
- Excel粘贴自定义分隔符的文本
- SecureCrt自动生成log 设置图解
- 迟到的2021回顾和总结