01.Android崩溃Crash封装库
目录介绍
- 01.该库具有的功能
- 02.该库优势分析
- 03.该库如何使用
- 04.降低非必要crash
- 05.异常恢复原理
- 06.后续的需求说明
- 07.异常栈轨迹原理
- 08.部分问题反馈
- 09.其他内容说明
01.该库具有的功能
1.1 功能说明
- 异常崩溃后思考的一些问题
- 1.是否需要恢复activity栈,以及所在崩溃页面数据
- 2.crash信息保存和异常捕获,是否和百度bug崩溃统计sdk等兼容。是否方便接入
- 3.是否要回到栈顶部的那个activity(保存栈信息)
- 4.崩溃后需要收集哪些信息。手机信息,app信息,崩溃堆栈,内存信息等
- 5.异常崩溃如何友好退出,以及崩溃后调用重启app是否会出现数据异常
- 6.针对native代码崩溃,如何记录日志写到文件中
- 该库可以做一些什么
- 1.在Android手机上显示闪退崩溃信息,并且崩溃详情信息可以保存,分享给开发
- 主要是测试同学在测试中发现了崩溃,然后跑过去跟开发说,由于不容易复现导致开发童鞋不承认……有时候用的bug统计不是那么准!
- 2.对于某些设备,比如做Kindle开发,可以设置崩溃重启app操作
- 3.暴露了用户上传自己捕获的crash数据,以及崩溃重启的接口监听操作
- 4.一个崩溃日志保存到一个文件中,文件命名规则【版本+日期+异常】:V1.0_2020-09-02_09:05:01_java.lang.NullPointerException.txt
- 5.崩溃日志list可以获取,支持查看日志详情,并且可以分享,截图,以及复制崩溃信息
- 6.收集崩溃日志包括,设备信息,进程信息,崩溃信息(Java崩溃、Native崩溃 or ANR)
- 7.收集崩溃时的内存信息(OOM、ANR、虚拟内存耗尽等,很多崩溃都跟内存有直接关系),完善中
- 1.在Android手机上显示闪退崩溃信息,并且崩溃详情信息可以保存,分享给开发
1.2 截图如下所示

1.3崩溃后日志记录

1.4 崩溃流程图

02.该库优势分析
- 低入侵性接入该lib,不会影响你的其他业务。暴露崩溃重启,以及支持开发者自己捕获crash数据的接口!能够收集崩溃中的日志写入文件,记录包括设备信息,进程信息,崩溃信息(Java崩溃、Native崩溃 or ANR),以及崩溃时内存信息到file文件中。支持用户获取崩溃列表,以及跳转崩溃日志详情页面,并且可以将崩溃日志分享,截长图,复制等操作。可以方便测试和产品给开发提出那种偶发性bug的定位日志,免得对于偶发行崩溃,开发总是不承认……开发总是不承认……
03.该库如何使用
- 如何引入该库
implementation 'cn.yc:ToolLib:1.0.0'
//GitHub代码
https://github.com/yangchong211/YCAndroidTool
- 初始化代码如下所示。建议在Application中初始化……
CrashHandler.getInstance().init(this, new CrashListener() {
/**
* 重启app
*/
@Override
public void againStartApp() {
CrashToolUtils.reStartApp1(App.this,1000);
//CrashToolUtils.reStartApp2(App.this,1000, MainActivity.class);
//CrashToolUtils.reStartApp3(AppManager.getAppManager().currentActivity());
} /**
* 自定义上传crash,支持开发者上传自己捕获的crash数据
* @param ex ex
*/
@Override
public void recordException(Throwable ex) {
//自定义上传crash,支持开发者上传自己捕获的crash数据
//StatService.recordException(getApplication(), ex);
}
});
- 关于重启App的操作有三种方式api
//开启一个新的服务KillSelfService,用来重启本APP【使用handler延迟】
CrashToolUtils.reStartApp1(App.this,1000);
//用来重启本APP[使用闹钟,整体重启,临时数据清空(推荐)]
CrashToolUtils.reStartApp2(App.this,1000, MainActivity.class);
//检索获取项目中LauncherActivity,然后设置该activity的flag和component启动app【推荐】
CrashToolUtils.reStartApp3(AppManager.getAppManager().currentActivity());
- 关于获取崩溃目录api
//崩溃文件存储路径:/storage/emulated/0/Android/data/你的包名/cache/crashLogs
//崩溃页面截图存储路径:/storage/emulated/0/Android/data/你的包名/cache/crashPics
String crashLogPath = ToolFileUtils.getCrashLogPath(this);
String crashPicPath = ToolFileUtils.getCrashPicPath(this);
- 关于崩溃日志记录
- 日志记录路径:/storage/emulated/0/Android/data/你的包名/cache/crashLogs
- 日志文件命名:V1.0_2020-09-02_09:05:01_java.lang.NullPointerException.txt【版本+日期+异常】
- 关于跳转错误日志list列表页面
- 跳转日志列表页面如下所示,这里调用一行代码即可。点击该页面list条目即可进入详情
CrashToolUtils.startCrashListActivity(this);
- 那么如何获取所有崩溃日志的list呢。建议放到子线程中处理!!
List<File> fileList = ToolFileUtils.getCrashFileList(this); //如果是要自己拿到这些文件,建议根据时间来排个序
//排序
Collections.sort(fileList, new Comparator<File>() {
@Override
public int compare(File file01, File file02) {
try {
//根据修改时间排序
long lastModified01 = file01.lastModified();
long lastModified02 = file02.lastModified();
if (lastModified01 > lastModified02) {
return -1;
} else {
return 1;
}
} catch (Exception e) {
return 1;
}
}
});
- 如何删除单个文件操作
//返回true表示删除成功
boolean isDelete = ToolFileUtils.deleteFile(file.getPath());
- 如何删除所有的文件。建议放到子线程中处理!!
File fileCrash = new File(ToolFileUtils.getCrashLogPath(CrashListActivity.this));
ToolFileUtils.deleteAllFiles(fileCrash);
- 如何获取崩溃文件中的内容
//获取内容
String crashContent = ToolFileUtils.readFile2String(filePath);
- 还有一些关于其他的api,如下。这个主要是方便测试同学或者产品,避免开发不承认那种偶发性崩溃bug……
//拷贝文件,两个参数分别是源文件,还有目标文件
boolean copy = ToolFileUtils.copyFile(srcFile, destFile);
//分享文件。这个是调用原生的分享
CrashLibUtils.shareFile(CrashDetailsActivity.this, destFile);
//截图崩溃然后保存到相册。截图---> 创建截图存储文件路径---> 保存图片【图片质量,缩放比还有采样率压缩】
final Bitmap bitmap = ScreenShotsUtils.measureSize(this,view);
String crashPicPath = ToolFileUtils.getCrashPicPath(CrashDetailsActivity.this) + "/crash_pic_" + System.currentTimeMillis() + ".jpg";
boolean saveBitmap = CrashLibUtils.saveBitmap(CrashDetailsActivity.this, bitmap, crashPicPath);
05.异常恢复原理
- 第一种方式,开启一个新的服务KillSelfService,用来重启本APP。
CrashToolUtils.reStartApp1(App.this,1000);
- 第二种方式,使用闹钟延时,然后重启app
CrashToolUtils.reStartApp2(App.this,1000, MainActivity.class);
- 第三种方式,检索获取项目中LauncherActivity,然后设置该activity的flag和component启动app
CrashToolUtils.reStartApp3(AppManager.getAppManager().currentActivity());
- 关于app启动方式详细介绍
06.后续的需求说明
- 可能不兼容
- 该库尚未通过多进程应用程序进行测试。如果您使用这种配置进行测试,请提供反馈!
- 如果您的应用程序初始化监听或错误活动崩溃,则有可能进入无限重启循环(在大多数情况下,库会对此进行检查,但在极少数情况下可能会发生)。
- 修复Android P反射限制导致的Activity生命周期异常无法finish Activity问题。某些机型还是不兼容……
- App崩溃收集信息说明
- 收集崩溃时的基本信息
- 进程(前台进程还是后台进程)
- 线程(是否是 UI 线程)
- 崩溃堆栈(具体崩溃在系统的代码,还是我们自己的代码里面)
- 崩溃堆栈类型(Java 崩溃、Native 崩溃 or ANR)
- 收集崩溃时的系统信息
- 机型、系统、厂商、CPU、ABI、Linux 版本等。(寻找共性)
- Logcat。(包括应用、系统的运行日志,其中会记录 App 运行的一些基本情况)
- 收集崩溃时的内存信息(OOM、ANR、虚拟内存耗尽等,很多崩溃都跟内存有直接关系)
- 系统剩余内存。(系统可用内存很小 – 低于 MemTotal 的 10%时,OOM、大量 GC、系统频繁自杀拉起等问题都非常容易出现)
- 虚拟内存(但是很多类似OOM、tgkill 等问题都是虚拟内存不足导致的)
- 应用使用内存(得出应用本身内存的占用大小和分布)
- 线程数
- 收集崩溃时的应用信息
- 崩溃场景(崩溃发生在哪个 Activity 或 Fragment,发生在哪个业务中)
- 关键操作路径(记录关键的用户操作路径,这对我们复现崩溃会有比较大的帮助)
- 其他自定义信息(不同应用关心的重点不一样。例如运行时间、是否加载了补丁、是否是全新安装或升级等)
- 收集崩溃时的基本信息
07.异常栈轨迹原理
- Android发生异常为何崩溃
- 一旦线程出现抛出异常,并且我们没有捕捉的情况下,JVM将调用Thread中的dispatchUncaughtException方法把异常传递给线程的未捕获异常处理器。发现最后会使用到Thread.getDefaultUncaughtExceptionHandler()
- 既然Android遇到异常会发生崩溃,然后找一些哪里用到设置setDefaultUncaughtExceptionHandler,即可定位到RuntimeInit类。
- 具体可以找到RuntimeInit类,然后在找到KillApplicationHandler类。首先看该类的入口main方法--->commonInit()--->,然后接着往下走,找到setDefaultUncaughtExceptionHandler代码。当出现异常是try-catch,并且在finally中直接kill杀死app操作。
- 详细可以看:Android项目崩溃分析
- 崩溃后异常堆栈链是如何形成的
- 待完善,看:异常栈轨迹处理
08.部分问题反馈
- 该异常捕获实效了是什么情况?
- Thread.setDefaultUncaughtExceptionHandler(handler) 方法如果被多次调用的话,会以最后一次传递的 handler 为准,所以如果用了第三方的统计模块,可能会出现失灵的情况。对于这种情况,在设置默认 hander 之前,可以先通过 getDefaultUncaughtExceptionHandler() 方法获取并保留旧的 hander,然后在默认 handler 的uncaughtException 方法中调用其他 handler 的 uncaughtException 方法,保证都会收到异常信息。
- 关于上传日志介绍
- 设置该异常初始化后,在进入全局异常时系统就提示尽快收集信息,进程将被结束,因此不可以在此时做网络上传崩溃信息。可以在此时将错误日志写入到file文件或者sp中。
- 比如:通过SharedPreferences将错误日志的路径写入配置文件中,在启动的时候先检测该配置文件是否有错误日志信息,如果有则读取文件,然后实现日志上传。上传完成后删除该sp文件……
- 使用looper可以拦截崩溃和anr吗
- 可以实现拦截UI线程的崩溃,耗时性能监控。但是也并不能够拦截所有的异常。如果在Activity的onCreate出现崩溃,导致Activity创建失败,那么就会显示黑屏。
- fork出app进程后,在ActivityThread中,在main方法的最后调用了 Looper.loop(),在这个方法中处理主线程的任务调度,一旦执行完这个方法就意味着APP被退出了。
- 果主线程发生了异常,就会退出循环,意味着APP崩溃,所以我们我们需要进行try-catch,避免APP退出,再启动一个 Looper.loop() 去执行主线程任务,就不会退出。
- looper拦截崩溃或者anr,存在一个巨大的问题,就是按钮点不动或者无反应。有可能导致出现其他问题……这个需要慎重使用
09.其他内容说明
- 混淆
- -keep class com.yc.toollib.** { *; }
- -keepnames class com.yc.toollib.** { *; }
- 该库笔记介绍
- 其他项目推荐
该开源库地址:https://github.com/yangchong211/YCAndroidTool
01.Android崩溃Crash封装库的更多相关文章
- 获取Android崩溃crash信息并写入日志发送邮件
一.实现Thread.UncaughtExceptionHandlerUnChecked异常发生时,由于没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将退出,也就是我们 ...
- okhttputils【 Android 一个改善的okHttp封装库】使用(一)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本文使用的OKHttp封装库是张鸿洋(鸿神)写的,因为在项目中一直使用这个库,所以对于一些常用的请求方式都验证过,所以特此整理下. ...
- Android 一个改进的okHttp封装库
一.概述 之前写了篇Android OkHttp完全解析 是时候来了解OkHttp了,其实主要是作为okhttp的普及文章,当然里面也简单封装了工具类,没想到关注和使用的人还挺多的,由于这股热情,该工 ...
- android 程序崩溃crash日志的捕捉
android 程序崩溃crash日志的捕捉 之前在项目开发过程中,一直会遇到程序崩溃了,但是测试組的哥哥们又没及时的导出日志.... 后来在诳群的时候听别人说起,腾讯有那么一个叫bugly的东西 将 ...
- Android 一个改善的okHttp封装库
膜拜一下~ 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49734867: 本文出自:[张鸿洋的博客] 一.概述 之前写了篇A ...
- 毕加索的艺术——Picasso,一个强大的Android图片下载缓存库,OkHttpUtils的使用,二次封装PicassoUtils实现微信精选
毕加索的艺术--Picasso,一个强大的Android图片下载缓存库,OkHttpUtils的使用,二次封装PicassoUtils实现微信精选 官网: http://square.github.i ...
- okhttputils【 Android 一个改善的okHttp封装库】使用(三)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这一篇主要讲一下将OkHttpUtils运用到mvp模式中. 数据请求地址:http://www.wanandroid.com/to ...
- # 095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 03 封装总结 01 封装知识点总结
095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
- 094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 04 static关键字(续)
094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
- 093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 03 static关键字(下)
093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
随机推荐
- delphi中的退出程序的确认问题
在formclose中用if Application.MessageBox('你确认要退出吗?','请确认',MB_YesNo+MB_IconQuestion)=IDno then begin ... ...
- ASP.NET Core分布式项目实战(运行Consent Page)--学习笔记
任务21:运行Consent Page 修改 Config.cs 中的 RequireConsent 为 true,这样登录的时候就会跳转到 Consent 页面 修改 ConsentControll ...
- 了解一下基本的http代理配置
我们首先用一个简单例子了解一下基本的http代理配置 worker_processes 1; #nginx worker 数量 error_log logs/error.log; #指定错误日志文件路 ...
- 100 行代码实现用户登录注册与 RESTful 接口 - 手把手教程附 Python 源码
在开发大多数应用时,用户系统都是必不可少的部分,而我们总是需要开发围绕用户的登录,注册,获取,更新等接口.在这篇文章将带你用一百多行代码简洁地实现一套这样的用户鉴权与 RESTful 接口,并使用 S ...
- fmt、变量、常量
fmt包 fmt包主要用于打印数据,常用的有Printf.Print.Printf // 文件所属包 package main // 导入fmt包,主要用于打印数据 import "fmt& ...
- Java设计模式-装饰者模式Decorator
介绍 装饰者模式的核心思想是通过创建一个装饰对象(即装饰者),动态扩展目标对象的功能,并且不会改变目标对象的结构,提供了一种比继承更灵活的替代方案.需要注意的是,装饰对象要与目标对象实现相同的接口,或 ...
- spring boot+bootstrap实现动态轮播图实战
1.bootstrap轮播图 最近开发了个网站需要用到轮播图,正好前端用的是Bootstrap,这里就实战一下. 水平一般能力有限,仅供参考. 前提条件: bootstrap4.5 jquery 3张 ...
- Redis分布式锁的正确使用姿势
前言 分布式锁在日常开发中,用处非常的多.包括但不限于抢红包,秒杀,支付下单,幂等,等等场景. 分布式锁的实现方式有多种,包括redis实现,mysql实现,zookeeper实现等等.而其中redi ...
- ASP.NET 上传文件导入Excel
前言 本文对应的场景是导入Excel数据,Excel对应的字段都配置在xml文件中.截图如下: 代码实战 工具类 实体类:XMLReadModel.cs public class XMLReadMod ...
- macOS Monterey 与以下电脑兼容下载操作流程解析
有时在开发iOS应用时我们时常遇到各种情况,比如手机升级了Xcode不支持这时候需要安装xcode但是xcode需要依奈相应系统本人小编整理了这种情况无法解决问题. 首相打开苹果标志进入到下面界面 进 ...