Android Crash 全局捕获
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 全局捕获的更多相关文章
- Android进阶——Crash异常捕获并发送到服务器
在项目中,我们常常会遇到Crash的现象,也就是程序崩溃的时候,这个时候最常看到的就是这个界面 如果你的项目已经发布到市场上了,这样的崩溃对于开发人员是看不到的,所以我们得想方法将崩溃信息发送到服务器 ...
- Android app 全局异常统一处理
异常处理需求 Android app 出现 crash 时,会出现 "程序异常退出" 的提示并关闭,体验不好,另外主要是无法知道哪里出现的崩溃,需要知道哪里造成的异常,就需要一个全 ...
- Android Crash 定位
本文介绍了如何在 Android 手机发生 Crash 时进行 Log 分析的方法, 它可以帮助测试人员快速定位 Android 手机 Crash 发生的原因,同时给研发人员提供有效修改 Bug 的 ...
- android中全局异常捕捉
android中全局异常捕捉 只要写代码就会有bug,但是我们要想办法收集到客户的bug.有第三方bugly或者友盟等可以收集.但是,android原生就提供了有关收集异常的api,所以我们来学习一下 ...
- Android获取全局Context的方法
Android获取全局Context的方法 Android--应用全局获取Context - 超宇的博客 - CSDN博客https://blog.csdn.net/chaoyu168/article ...
- 拖拽demo--兼容--全局捕获
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 保留全部Android crash信息
保留全部Android crash信息 framework/base/core/java/com/android/internal/os/RuntimeInit.java 又一次以下这个函数,增加自己 ...
- 关于TornadoFx和Android的全局配置工具类封装实现及思路解析
原文地址: 关于TornadoFx和Android的全局配置工具类封装实现及思路解析 - Stars-One的杂货小窝 目前个人开发软件存在设置页面,可以让用户自定义些设置,但我发现,存储数据的代码逻 ...
- Android使用UncaughtExceptionHandler捕获全局异常
Android系统的“程序异常退出”,给应用的用户体验造成不良影响.为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理.通过Thread.setDe ...
随机推荐
- Canvas createRadialGradient API
Canvas createRadialGradient API <!DOCTYPE html> <html lang="en"> <head> ...
- GreenDao 3.2.0 的基本使用
前言 Android开发中我们或多或少都会接触到数据库.Android中提供了一个占用内存极小的关系型数据库-SQLite.虽然Android系统中提供了许多操作SQLite的API,但是我们还是需要 ...
- Top K问题的两种解决思路
Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如: 从20亿个数字的文本中,找出最大的前100个. 解决Top K问题有两种思路, 最直观:小顶堆(大顶堆 -> 最小1 ...
- 微信小程序开发系列(二)小程序的全局文件
其实你已经知道了小程序的文件结构 上一节讲到,小程序的页面由三部分组成: 视图(.wxml).逻辑(.js).样式(.wxss). 我们这次重新展开文件结构: 小程序用到的文件类型只有四种,正如你所看 ...
- CodeForces758D
D. Ability To Convert time limit per test:1 second memory limit per test:256 megabytes input:standar ...
- SQL关键字转换大写核心算法实现
1 不跟你多废话 上代码! /// <summary> /// SQL关键字转换器 /// </summary> public class SqlConverter : IKe ...
- JS与浏览器的几个兼容性问题
第一个:有的浏览器不支持getElementsByClassName(),所以需要写一个function()来得到需要标签的class,然后进行class的增加.删除等操作. 第二个:在需要得到特定标 ...
- Linux下使用javac编译
Linux下使用javac编译Hadoop程序 首先要配置好Hadoop, 给出两个教程 Hadoop安装教程单机/伪分布式配置Hadoop2.6.0/Ubuntu14.04 Hadoop集群安装配置 ...
- SQLite:自学笔记(1)——快速入门
SQLite的安装和入门 了解 啥是SQLite? SQLite是一种轻巧迷你的关系型数据库管理系统.它的特点如下: 不需要一个单独的服务器进程或操作的系统(无服务器的). SQLite 不需要配置, ...
- 代码神器Atom,最常用的几大插件,你值得拥有。
作者:魔洁 atom常用插件 atom插件安装File>Settings>intall搜索框输入插件名,点击Packages搜索,搜索出来后点击intall安装,建议你先安装(simpli ...