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 ...
随机推荐
- Recurrent Neural Network系列2--利用Python,Theano实现RNN
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...
- 创建 OVS vlan101 并部署 instance - 每天5分钟玩转 OpenStack(139)
前面我们创建了 OVS vlan100 并部署了 instance,今天继续创建 vlan101. subnet IP 地址为 172.16.101.0/24. 底层网络发生了什么变化 Neutron ...
- Hadoop权威指南:从Hadoop URL读取数据
[TOC] Hadoop权威指南:从Hadoop URL读取数据 使用java.net.URL对象从Hadoop文件系统读取文件 实现类似linux中cat命令的程序 文件名 HDFSCat.java ...
- Dubbo源码学习文章目录
目录 Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 Dubbo源码学习--注册中心分析 Dubbo源码学习--集群负载均衡算法的实现
- 源码(04) -- java.util.List<E>
java.util.List<E> 源码分析(JDK1.7) --------------------------------------------------------------- ...
- 如何在Oracle中复制表结构和表数据 【转载】
1. 复制表结构及其数据: create table table_name_new as select * from table_name_old 2. 只复制表结构: create table ta ...
- linux下读取系统内存的demo
#include <stdio.h> #define KIBIBYTE_SIZE 1024LL #define MEBIBYTE_SIZE 1048576LL #define GIBIBY ...
- 微端游戏启动器launcher的制作(序篇)
公司要做一个游戏接入腾讯QQ游戏大厅,腾讯要求制作一个launcher,公司之前并没有接入过腾讯,所以大家其实都不懂,而我又是新人,所以刚拿到这个任务的时候整个人就是一个大写的懵逼.在网上查找了不少的 ...
- 解决maven 下载 hadoop-client 客户端 报错的问题
第一.pom.xml配置: <dependency> <groupId>org.apache.hadoop</groupId> <artifactId> ...
- 抛砖引玉:探讨网站性能优化之Javascript异步懒加载技术
懒加载技术是现在许多大型网站的都使用的提高网站性能的方式,它的核心思想是当用户想看页面某个区域时,再加载该区域的数据.这在一定程度上减轻了服务器端的压力,也加快了页面的呈现速度. 其实国内很多网站都用 ...