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. Fiddler 模拟请求的操作方法

    此文记录使用Fidder Web Debugger工具,模拟请求的操作步骤! 首先简述一下fiddler的使用: 1.下载安装Fidder抓包工具. 2.打开fiddler发现有左边的栏有请求的url ...

  2. HDU 4570(区间dp)

    E - Multi-bit Trie Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u ...

  3. android ExpandableListView实现不同的布局

    最近有一个需求要实现listview的不同布局!因为有好几上header,就想到了ExpandableListView! 这个是我的需求模型:看图(自己画的) 然后百度~google~发帖~总算有点效 ...

  4. ubuntu 14.04 中找不到 libgtk-x11-2.0.so

    如果ubuntu安装的64位的,在其中安装32位软件时就会碰到缺失libgtk-x11-2.0.so的情况 比如用wine安装qq时 启动qq时就会报这样的错误 error : cannot open ...

  5. 关于Task的一点思考和建议

    前言 本打算继续写SQL Server系列,接下来应该是死锁了,但是在.NET Core项目中到处都是异步,最近在写一个爬虫用到异步,之前不是很频繁用到异步,当用到时就有点缩手缩尾,怕留下坑,还是小心 ...

  6. Vue.js 系列教程 ①

    原文:intro-to-vue-1-rendering-directives-events 译者:nzbin 如果要我用一句话描述使用 Vue 的经历,我可能会说“它如此合乎常理”或者“它提供给我需要 ...

  7. PHP反射之类的反射

    最近在琢磨如何用PHP实现站点的插件功能,需要用到反射,于是现学了一下,笔记如下: class Person { public $name = 'Lily'; public $gender = 'ma ...

  8. 解决IIE8不支持媒体查询的方法

    最近在解决UI问题时碰到以下浏览器不兼容性问题(本人属于UI业余操作者,很多想法就很业余了): 问题:IE8及其以下低版本IE浏览器在缩小窗口时,UI没有按照相应的要求显示窗口缩小时对应的布局:其他浏 ...

  9. Weex系列二、显示图片

    上次我们创建了一个简单的Weex的demo. 一.常用的类 WXSDKEngine:SDK开放的绝大多数接口都在此有声明. WXLog: 用来打印日志. WXDebugTool: weex提供的对外调 ...

  10. Javascript—①你好,世界!

    新手Perfect教程之Javascript教程①-你好,世界! 前言:不知道Javascript是什么东东的自行度娘或google一下 Javascript在html<head>和< ...