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. linux redis 和 windows redis 的安装

    Linux 下安装 下载地址:http://redis.io/download,下载最新文档版本. 本教程使用的最新文档版本为 2.8.17,下载并安装: $ wget http://download ...

  2. java算法 蓝桥杯 扶老奶奶街

    一共有5个红领巾,编号分别为A.B.C.D.E,老奶奶被他们其中一个扶过了马路. 五个红领巾各自说话: A :我和E都没有扶老奶奶 B :老奶奶是被C和E其中一个扶过大街的 C :老奶奶是被我和D其中 ...

  3. console用法大全

    对于前端开发者来说,在开发过程中需要监控某些表达式或变量的值的时候,用 debugger 会显得过于笨重,取而代之则是会将值输出到控制台上方便调试.最常用的语句就是console.log(expres ...

  4. Python爬虫基础

    前言 Python非常适合用来开发网页爬虫,理由如下: 1.抓取网页本身的接口 相比与其他静态编程语言,如java,c#,c++,python抓取网页文档的接口更简洁:相比其他动态脚本语言,如perl ...

  5. Eclipse TypeScript 安装

    一.设置网络代理  1)步骤--window -->>NetWork Conntions->  2)打开QQ IP代理找一个网速快的IP设置,建议使用美国的.. 二.Install ...

  6. 常用的JQ函数

    /// <reference path="jquery-1.8.0.min.js"> /* * DIV或元素居中 * @return */ jQuery.fn.mCen ...

  7. Java 异步 IO

         新的异步功能的关键点,它们是Channel 类的一些子集,Channel 在处理IO操作的时候需要被切换成一个后台进程.一些需要访问较大,耗时的操作,或是其它的类似实例,可以考虑应用此功能. ...

  8. C#npoi导出excel一些自己的看法

    之前转过一篇类似的文章,那个是用C#自带的excel类操作Excel的,还有一种在c#上操作excel的方法便是npoi了,npoi是poi的C#版本. npoi操作excel有两种形式,一种是hss ...

  9. arcpy.mapping常用四大件-MapDocument

    arcpy.mapping常用四大件-MapDocument by 李远祥 点开arcpy.mapping的帮助,可以看到其有限的几个类,看起来东西不是很多,但却是非常的使用.由于arcpy定位就是粗 ...

  10. iOS程序生命周期 AppDelegate

    iOS的应用程序的生命周期,还有程序是运行在前台还是后台,应用程序各个状态的变换,这些对于开发者来说都是很重要的. iOS系统的资源是有限的,应用程序在前台和在后台的状态是不一样的.在后台时,程序会受 ...