Android Crash 全局捕获

首先应该明白的一点是,Android在崩溃后会重新启动崩溃时的那个Activity,如果你的Activity在初始化的时候就直接崩溃,那么你将连续得到 Crash 崩溃日志.这个说出来可能没什么,可怜的我在看到崩溃日志时活脱脱的以为 uncaughtException(Thread thread, Throwable ex) 方法被调用了两次.知道原因后就很好解决,在崩溃时把 Activity 栈清空就可以.

1. UncaughtExceptionHandler

这是一个接口,只有一个方法 uncaughtException(Thread t, Throwable e) 而且注释已经说明,这个方法是虚拟机(JVM)去调用.所以我们编写一个类实现此接口就可以了.

    public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}

2. 异常时的常规处理

1. 显示崩溃前的Toast

2. 保存崩溃日志信息到sd卡

3. 重启APP

实际项目中,我们需要做好这三件事.

    /**
* 异常发生时,系统回调的函数,我们在这里处理一些操作
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
showCrashToast();//展示崩溃前的Toast
saveCrashReport2SD(mContext, ex);//保存崩溃信息到sdcard
restartApp();//重新启动APP
}

3. 完整的代码

需要注意的地方写在注释里了.

public class CrashHandler implements UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
private Context mContext;
private static CrashHandler mInstance = new CrashHandler();
private CrashHandler() {
} /**
* 单例模式,保证只有一个CrashHandler实例存在
*
* @return
*/
public static CrashHandler getInstance() {
return mInstance;
} /**
* 异常发生时,系统回调的函数,我们在这里处理一些操作
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
showCrashToast();
saveCrashReport2SD(mContext, ex);
restartApp();
} /**
* 为我们的应用程序设置自定义Crash处理
*/
public void initCrashHandler(Context context) {
mContext = context;
Thread.setDefaultUncaughtExceptionHandler(this);
} private void restartApp() {
Intent intent = new Intent(App.getInstance().getApplicationContext(),
InitAdvsMultiActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent restartIntent = PendingIntent.getActivity(App.getInstance()
.getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
//重启应用
AlarmManager mgr = (AlarmManager) App.getInstance().getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis(), restartIntent); //清空Activity栈,防止系统自动重启至崩溃页面,导致崩溃再次出现.
ActivityLifeManager.getInstance().finishAllActivity();
//退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
System.gc();
} private void showCrashToast() {
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(App.getInstance().getApplicationContext(), "很抱歉,程序出现异常,即将重启",
Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
try {
Thread.sleep(1000);//Toast展示的时间
} catch (InterruptedException e) {
}
} /**
* 获取一些简单的信息,软件版本,手机版本,型号等信息存放在LinkedHashMap中
*
* @param context
* @return
*/
private HashMap<String, String> obtainSimpleInfo(Context context) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
PackageManager mPackageManager = context.getPackageManager();
PackageInfo mPackageInfo = null;
try {
mPackageInfo = mPackageManager.getPackageInfo(context.getPackageName(),
PackageManager.GET_ACTIVITIES);
} catch (NameNotFoundException e) {
e.printStackTrace();
} map.put("APP", "AppName");
map.put("用户名", SharedPreferencesUtils.getInstance().getUserName());
map.put("品牌", "" + Build.BRAND);
map.put("型号", "" + Build.MODEL);
map.put("SDK版本", "" + Build.VERSION.SDK_INT);
map.put("versionName", mPackageInfo.versionName);
map.put("versionCode", "" + mPackageInfo.versionCode);
map.put("crash时间", parserTime(System.currentTimeMillis())); return map;
} /**
* 获取系统未捕捉的错误信息
*
* @param throwable
* @return
*/
private String obtainExceptionInfo(Throwable throwable) {
StringWriter mStringWriter = new StringWriter();
PrintWriter mPrintWriter = new PrintWriter(mStringWriter);
throwable.printStackTrace(mPrintWriter);
mPrintWriter.close(); Log.e(TAG, mStringWriter.toString());
return mStringWriter.toString();
} /**
* 保存获取的 软件信息,设备信息和出错信息保存在SDcard中
*
* @param context
* @param ex
* @return
*/
private String saveCrashReport2SD(Context context, Throwable ex) {
String fileName = null;
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : obtainSimpleInfo(context).entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key).append(" = ").append(value).append("\n");
}
sb.append(obtainExceptionInfo(ex));
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(CrashConstant.CRASH_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
try {
fileName = dir.toString() + File.separator + parserTime(System.currentTimeMillis()) +".txt";
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(sb.toString().getBytes());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return fileName;
} /**
* 将毫秒数转换成yyyy-MM-dd-HH-mm-ss的格式,并在后缀加入随机数
*
* @param milliseconds
* @return
*/
private String parserTime(long milliseconds) {
System.setProperty("user.timezone", "Asia/Shanghai");
TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
TimeZone.setDefault(tz);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return format.format(new Date(milliseconds));
}
}

Android Crash 全局捕获的更多相关文章

  1. Android进阶——Crash异常捕获并发送到服务器

    在项目中,我们常常会遇到Crash的现象,也就是程序崩溃的时候,这个时候最常看到的就是这个界面 如果你的项目已经发布到市场上了,这样的崩溃对于开发人员是看不到的,所以我们得想方法将崩溃信息发送到服务器 ...

  2. Android app 全局异常统一处理

    异常处理需求 Android app 出现 crash 时,会出现 "程序异常退出" 的提示并关闭,体验不好,另外主要是无法知道哪里出现的崩溃,需要知道哪里造成的异常,就需要一个全 ...

  3. Android Crash 定位

    本文介绍了如何在 Android 手机发生 Crash 时进行 Log 分析的方法, 它可以帮助测试人员快速定位 Android 手机 Crash 发生的原因,同时给研发人员提供有效修改 Bug 的 ...

  4. android中全局异常捕捉

    android中全局异常捕捉 只要写代码就会有bug,但是我们要想办法收集到客户的bug.有第三方bugly或者友盟等可以收集.但是,android原生就提供了有关收集异常的api,所以我们来学习一下 ...

  5. Android获取全局Context的方法

    Android获取全局Context的方法 Android--应用全局获取Context - 超宇的博客 - CSDN博客https://blog.csdn.net/chaoyu168/article ...

  6. 拖拽demo--兼容--全局捕获

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 保留全部Android crash信息

    保留全部Android crash信息 framework/base/core/java/com/android/internal/os/RuntimeInit.java 又一次以下这个函数,增加自己 ...

  8. 关于TornadoFx和Android的全局配置工具类封装实现及思路解析

    原文地址: 关于TornadoFx和Android的全局配置工具类封装实现及思路解析 - Stars-One的杂货小窝 目前个人开发软件存在设置页面,可以让用户自定义些设置,但我发现,存储数据的代码逻 ...

  9. Android使用UncaughtExceptionHandler捕获全局异常

    Android系统的“程序异常退出”,给应用的用户体验造成不良影响.为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理.通过Thread.setDe ...

随机推荐

  1. .NET操作RabbitMQ组件EasyNetQ使用中文简版文档。

    本文出自EasyNetQ官方文档,内容为自己理解加翻译.文档地址:https://github.com/EasyNetQ/EasyNetQ/wiki/Quick-Start EasyNetQ简介 Ea ...

  2. MEAN教程2-Nodejs安装

    安装Node.js稳定版本最简单的办法也是使用二进制文件,Node.js官方网站上提供了下载地址,可用于Linux.Mac OS X和Windows系统.同样要注意下载与目标操作系统架构一致的文件. ...

  3. Win下JDK的安装和简单使用教程

    下载安装 一.从官网下载 1.百度jdk 然后点击像图片中指出的那个链接(www.oracle.com是java的官网) 2.下载(先点击那个 选择框 同意许可协议) 然后根据自己的电脑选择下载 64 ...

  4. ArcGIS Pro 简明教程(4)工具和模型构建器

    ArcGIS Pro 简明教程(4)工具和模型构建器 by 李远祥 工具箱中的工具 ArcGIS Pro 在1.3版本基本上已经继承了ArcMap的所有工具,而且会不断加入一些它自身才有的工具,例如适 ...

  5. bootstrap3 响应式布局栅格式布局

    抓住重点 下面开始实现Bootstrap版本3的Demo 案例 首先去官方网站  http://www.bootcss.com/ 下载 点击 进入 点击 进入 下载 把 相关的js和css 拷贝到项目 ...

  6. devexpress显示缓冲滚动条与实现类似QQ消息推送效果

    1.一般在项目中处理大数据,或者查询大量数据时,耗时会很长,这个时候缓冲条是必不可少的.这里展示一个devexpress不错的缓冲条,如图所示: 使用到了控件splashScreenManager,运 ...

  7. pl/sql 导出oracle表结构

    tools->export tables 是导出表结构还有数据 tools->export user objects是导出表结构   可以用tools->export tables ...

  8. JMeter使用简单教程

    去Apache JMeter官网下载最新的Windows下的zip安装包并解压     进入JMeter安装目录下的bin目录,双击jmeter.bat,运行JMeter程序     打开测试计划主界 ...

  9. WPF - 监听判断键盘组合键的按下

    对于键盘事件PreviewKeyDown.PreviewKeyUp.KeyDown.KeyUp,在其中检查当次事件是哪个按键触发的很简单,只需要判断KeyEventArgs类型的事件参数e的Key属性 ...

  10. 【数据标识】iOS App下载渠道的统计需求

    需求概述 我们现在有一个需求,某一个活动需要拉新所谓的拉新一般是推App下载,这个用户通过这个活动下载了App后,我们需要做到[在数据库中记录这个用户下载这个App是通过那个二维码渠道的,从效果上说, ...