| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 开发工具 -> 如何避免Android运行时崩溃,保证程序高可用性一 -> 正文阅读 |
|
[开发工具]如何避免Android运行时崩溃,保证程序高可用性一 |
1.Crash是什么?Crash,即闪退,多指在移动设备(如IOS、Android设备)中,在打开应用程序时出现突然退出中断的情况(类似于Windows的应用程序崩溃)。 2.什么引起Crash?异常可以简单分为Checked异常及Unchecked异常,那么这两种异常的区别是什么呢?其中派生于Error或者RuntimeException异常称为Unchecked异常,所有其他的Exception称为Checked异常。 那么为什么要这样区分他们呢?因为Java compiler(编译器)强制要求所有的Exception要么被catch,要么被throw对其进行处理,否则编译会不通过,除非这是一个RuntimeException(e instanceof RuntimeException)。也就是说,通常的Exception一定要被处理,也即我们所说的Checked Exception,而RuntimeException/Error,编译器是不强制要求处理的,所以被称为UnChecked exception。 RuntimeException(运行时异常),它属于Unchecked异常。如果出现RuntimeException,那么一定是程序员代码的问题,编译器并不会检查Unchecked异常。在开发过程中,我们遇到的crash绝大多数都属于RuntimeException(RuntimeException是引起Crash主要原因); 3.异常分类分哪些种?Java层 ?从上图可以看出,他们都是从Throwable继承而来的,Throwable下层分为两个子类:Error和Exception。 3.1关于Error和Exception其中Error类描述了Java运行时系统的内部错误或设备资源耗尽的错误。?这种错误一般没有别的解决办法,它用于报告给开发者程序无法恢复的异常情况。对于所有Error类型以及其子类都不要求程序进行处理,常见如栈溢出StackOverflowError等。 而Exception类则是值程序有可能恢复的异常情况,Exception包含了运行时异常(Runtime Exception)和受检查的异常(Checked Exception); 3.2关于Checked和Unchecked异常上面一小节提到了Checked异常及Unchecked异常,那么这种异常的区别是什么呢?其中派生于Error或者RuntimeException的异常称为Unchecked异常,所有其他的Exception称为Checked异常。在上图所示中,浅蓝色方框所标注的为Unchecked异常。 那么为什么要这样区分他们呢?因为Java compiler(编译器)强制要求所有的Exception要么被catch,要么被throw对其进行处理,否则编译会不通过,除非这是一个RuntimeException(e instanceof RuntimeException)。也就是说,通常的Exception一定要被处理,也即我们所说的Checked Exception,而RuntimeException/Error,编译器是不强制要求处理的,所以被称为UnChecked exception。 3.3关于RuntimeExceptionOracle 官网解释: 4.Crash崩溃率的统计影响用户体验因素: App的应用性能稳定是良好用户体验中非常关键的一环,而现实情况却是应用崩溃、卡顿、加载缓慢、页面白屏等问题,频频出现在用户的真实体验之中,成为影响业务表现的直接杀手。为此,应用性能管理(APM)正在国内外蓬勃发展,被越来越多的企业所认可。 友盟崩溃率统计: 友盟+U-APM数据白皮书显示:APP 整体崩溃率为0.293%,其中Android 端崩溃率为0.32%, iOS 端崩溃率为0.1%,头部移动应用在治理崩溃表现方面表现更为优异,更加注重在应用质量治理方面的精细打磨。 参考: 移动应用性能体验报告-Android崩溃率达0.32%,OV、华为表现良好 5.线程如何处理一个未捕获异常导致的线程中断5.1Thread定义了UncaughtExceptionHandler异常处理器接口
5.2Thread定义两个UncaughtExceptionHandler成员变量
Thread中存在两个UncaughtExceptionHandler成员变量: 1)一个是静态的defaultUncaughtExceptionHandler:来自所有线程中的Exception在抛出并且未捕获的情况下,都会从此路过。进程fork的时候设置的就是这个静态defaultUncaughtExceptionHandler,管辖范围为整个进程。 2)另一个非静态uncaughtExceptionHandler:为单个线程设置一个属于线程自己的uncaughtExceptionHandler,管辖范围比较小。 当一个线程由于未捕获异常即将终止时,Java虚拟机将使用Thread的getDefaultUncaughtExceptionHandler()方法查询线程unCaughtException处理程序,并调用处理程序的uncaughtException方法,将线程和异常作为参数传递。一个线程如果没有设置uncaughtExceptionHandler,将使用线程所在的线程组来处理这个未捕获异常。线程组ThreadGroup实现UncaughtExceptionHandler,所以可以用来处理未捕获的异常。 ThreadGroup实现uncaughtException如下:
1)首先将异常消息通知给父线程组处理; 2)否则,尝试利用一个默认的defaultUncaughtExceptionHandler来处理异常; 3)如果没有默认的异常处理则将错误信息输出到System.err。 6.Android如何自定义添加全局接收Crash异常错误信息在Android中,我们同样可以使用UncaughtExceptionHandler来添加运行时异常的回调,来监控Crash发生; 6.1创建一个自定义UncaughtExceptionHandler类
6.2在Application子类内设置全局监控
完成以上2个步骤,我们就可以实现全局Crash监控了。这是所说的全局,是针对整个进程生效; 7.Android系统中Crash如何处理、分发逻辑上面我们了解了怎么在Android中补货Crash,实现Crash的监控,上报。那么Android中系统是如何处理、分发Crash的呢? 7.1异常处理的注册APP启动时,会通过zygote进程fork一个进程,然后创建VM虚拟机,然后会调用到zygoteInit进行初始化工作。 zygoteInit方法 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java的zygoteInit方法:
zygoteInit方法主要被zygote进程调用,zygoteInit调用了RuntimeInit.commonInit()方法; RuntimeInit.commonInit()方法
逻辑分析: 1)LoggingHandler主要处理打印日志,打印一个线程遇到的未捕获的异常信息; 2)Thead.setDefaultUncaughtExceptionHandler()用于注册系统默认异常处理的逻辑; 这里的RuntimeHooks.setUncaughtExceptionPreHandler()方法,其实是调用了Thread的setUncaughtExceptionPreHandler()方法; Android 8.0中,Thread类增加了一个接口叫setUncaughtExceptionPreHandler,它会注册在分发异常处理时的回调,用于Android系统(平台)使用; 我们先来看异常的分发逻辑,后面再分析KillApplicationHandler中对异常的处理逻辑; 异常的分发 Thread的dispatchUncaughtException负责处理异常的分发逻辑; Thread的dispatchUncaughtException
这里首先处理setUncaughtExceptionHandler注册的异常处理方法,然后调用通过setDefaultUncaughtExceptionHandler或者setUncaughtExceptionHandler方法注册的异常处理方法; 我们来看getUncaughtExceptionHandler()方法的返回值; Thread的getUncaughtExceptionHandler()方法
逻辑分析: 1)当uncaughtExceptionHandler不为空时,返回uncaughtExceptionHandler; uncaughtExceptionHandler是通过setUncaughtExceptionHandler方法注册异常处理Handler; 2)否则,返回group 3)这里的group,其实就是当前线程所在的线程组;并且线程组ThreadGroup同样实现了UncaughtExceptionHandler接口; TheadGroup的uncaughtException 在本文第一部分,我们其实已经介绍了,这里来回顾一下:
逻辑分析: 1)首先将异常消息通知给父线程组处理; 2)否则,尝试利用一个默认的defaultUncaughtExceptionHandler来处理异常; 3)如果没有默认的异常处理则将错误信息输出到System.err; 7.2异常的处理系统默认异常处理逻辑在KillApplicationHandler类的uncaughtException方法中,我们来看代码; KillApplicationHandler类的uncaughtException方法
逻辑分析: 1)调用ensureLogging(t,e)确保LoggingHandler的执行(有去重逻辑,不用担心重复执行); 2)然后调用了ActivityManager.getService().handleApplicationCrash()方法来进行处理; 3)最后调用Process.killProcess(Process.myPid())来杀死进程,并且退出VM; AMS的handleApplicationCrash方法 我们继续来看ActivityManagerService的handleApplicationCrash方法:
这里通过Application的binder,取得进程的ProcessRecord对象,然后调用handleApplicationCrashInner方法; AMS的handleApplicationCrashInner方法
这里处理一些错误日志的相关逻辑,然后调用AppErrors的crashApplication方法。 AppErrors的crashApplication方法 /frameworks/base/services/core/java/com/android/server/am/AppErrors.java
crashApplication调用crashApplicationInner方法,处理系统的crash弹框等逻辑,这里我们就不再详细分析了,感兴趣的可以看源代码了解一下; 到这里,关于系统默认的异常捕获及处理逻辑我们也就分析完成了。 8.Crash优化建议Crash是APP性能的一个非常重要的指标,我们要尽可能的减少Crash,增加APP的稳定性,一下是几点实际经验: 1)要有可靠的Crash日志收集方式:可以自己实现,也可以集成第三方SDK来采集分析; 2)当一个Crash发生了,我们不但需要针性的解决这一个Crash,而且要考虑这一类Crash怎么去解决和预防,只有这样才能使得该类Crash真正的解决,而不是反复出现。 9.总结?1)Java异常可分为:可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。 2)Java中,可以通过设置Thread类的uncaughtExceptionHandler属性或静态属性defaultUncaughtExceptionHandler来设置不可查异常的回调处理。 3)在Android中,运行时异常(属于不可查的异常),如果没有在try-catch语句捕获并处理,就会产生Crash,导致程序崩溃。 4)在Android中,我们同样可以使用UncaughtExceptionHandler来添加运行时异常的回调,来监控Crash的发生。 5)通过Thread的静态方法setDefaultUncaughtExceptionHandler方法,可以注册全局的默认Crash监控。通过Thread的setUncaughtExceptionHandler方法来注册某个线程的异常监控。 6)setDefaultUncaughtExceptionHandler方法和setUncaughtExceptionHandler方法有注册顺序的问题,多次注册后,只有最后一次生效。 7)Android系统中,默认的Crash处理Handler,是在进程创建时,通过RuntimeInit.commonInit()方法进行注册的。 8)Android 8.0中,Thread类增加了一个接口叫setUncaughtExceptionPreHandler,它会注册在分发异常处理时的回调,用于Android系统(平台)使用。 9)Thread的dispatchUncaughtException负责处理异常的分发逻辑。 10)Android中,异常分发顺序为: 4.1Crash解决思路 4.2Crash解决实例 参考: |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/16 6:34:13- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |