Android 崩溃优化之Java篇(二)

本文探讨了Android应用中Java层的崩溃类型,包括Error、Exception的区别,Checked和Unchecked异常,以及常见Java Exception & Error。重点讲解了NullPointerException、IndexOutOfBoundsException和OutOfMemoryError的预防和处理。同时,分析了崩溃堆栈、设备信息、用户操作路径等因素在排查问题中的作用,提出了预防崩溃的策略,如合理使用try-catch、代码审查和架构设计等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:本篇文章已授权微信公众号 YYGeeker 独家发布。
博主原创文章,转载请注明出处:小嵩的博客

一、前言

由于Android系统的碎片化、版本差异、厂商定制ROM等诸多原因,我们经常会遇到各种奇奇怪怪的崩溃,治理Android App的崩溃可谓是一个大老难题。对于一个大型应用来说,有时候可能一个很小的问题疏忽掉了,往往就可能影响成千上万的用户,最后对公司造成难以挽回的损失;也可能由于一个疏忽,导致整个团队都在加班加点花上数天时间去排查和解决问题。崩溃率是衡量一个应用质量的重要指标,作为一名开发者我们必须重视并尽力降低crash率。

本文从工作实践中总结了一些经验,希望能够为开发者个人或者其他团队提供一些解决方案的灵感和启发。权作抛砖引玉,有其他好的建议或者经验的可以交流讨论。本文讲述的是Java层崩溃,因此这里就再不提及Native相关的内容,Native层的相关知识点及经验分享会在后续文章单独讲述。

二、崩溃类型

Java 层

Throwable

从上图可以看出,它们都是从 Throwable 继承而来,Throwable 下一层分为两个子类:Error 和 Exception。

2.1 关于 Error 和 Exception

其中 Error 类描述了 Java 运行时系统的内部错误或设备资源耗尽的错误。这种错误一般没有别的解决办法,它用于报告给开发者程序无法恢复的异常情况。对于所有 Error 类型以及其子类都不要求程序进行处理,常见如内存溢出 StackOverflowError等。

而 Exception 类则是指程序有可能恢复的异常情况,Exception 包含了运行时异常(Runtime Exception)和受检查的异常(Checked Exception)

2.2 关于 Checked 和 Unchecked异常

上面一小节提到了 Checked 异常 及 Unchecked 异常,那么这两种异常的区别是什么呢? 其中,派生于 Error 或者 RuntimeException 的异常称为 Unchecked 异常,所有其他的 Exception 称为 Checked 异常。在上图所示中,浅蓝色方框所标注的为 Unchecked 异常。

那又为什么需要这样区分它们呢?因为 Java compiler (编译器) 强制要求所有的 Exception 要么被 catch,要么被 throw 对其进行处理,否则编译会不通过,除非这是一个 RuntimeExeption (e instanceof RuntimeException)。也就是说,通常的 Exception 一定要被处理,也即我们所说的 Checked Exception,而 RuntimeException / Error ,编译器是不强制要求处理的,所以被称为Unchecked exception。

2.3 关于 RuntimeException

Oracle 官网解释:
RuntimeException and its subclasses are unchecked exceptions. Unchecked exceptions do not need to be declared in a method or constructor’s throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.

RuntimeException (运行时异常),它属于 Unchecked 异常。如果出现RuntimeException,那么一定是程序员的代码问题,编译器并不会检查 Unchecked 异常。在开发过程中,我们遇到的crash 绝大多数都属于 RuntimeException。

2.4 常见 Java Exception & Error

从上面几点的介绍及描述,到这儿我们对Java 的异常类型已经有了一定认知,下面我们再挑几个最常见崩溃异常稍微讲一下:

2.4.1 NullPointerException

空指针异常崩溃(简称NPE)一般是崩溃占比较高、平时开发过程中频繁遇到的一种崩溃类型。总所周知,Java是粹面向对象的编程语言,一切皆为对象;在为空的对象中调用方法就会出现NullPointerException。

2.4.2 IndexOutOfBoundsException

用非法索引访问数组时抛出的异常,如果索引为负,或者大于等于数组大小,则该索引为非法索引。通常情况下,我们操作数组都需要对它的size做安全校验,在单线程操作数据的时候判断index 是否越界。

而在多线程下,IndexOutOfBoundsException 则会变得更加频繁和复杂。此时我们单纯对数组做一层index校验的代码已经变得不可靠,需要考虑多线程同时操作数据导致的问题。因此在多线程操作数据时,我们需要格外注意数据的可见性,可通过加锁/使用同步队列等方式,保持数据的同步以避免出现索引越界。

2.4.3 OutOfMemoryError

由于移动设备的性能有限性,内存溢出异常(简称OOM) 是Android中最常见 Error类型。在Android中导致OutOfMemoryError异常的常见原因主要有以下几种:

  • 内存中加载的数据量过于庞大,如大图内存占用过大;
  • 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
  • 代码中存在死循环或循环产生过多重复的对象实体;
  • 启动参数内存值设定的过小。

三、崩溃分析

作为程序员,排查定位crash比较考验我们的内功和耐心,有时可能因为一个很细节的点造成严重的crash事故,因此我们需要善于抓住各种蛛丝马迹来找出问题的根源。对于Java崩溃,我们可以从以下这些方面去侦察问题:

3.1 崩溃堆栈及异常类型

崩溃堆栈和异常类型是最直接也是最常见的一种方式,通过堆栈我们可以看到具体crash 的业务代码,以及其崩溃原因。这种是属于比较常见的,通常按照堆栈的代码及崩溃类型提示去修复即可。

3.2 设备信息

除了上述比较简单的崩溃分析,在遇到一些业务堆栈不明/系统疑难杂症等情况,我们就需要分析包括设备ID、系统版本、模拟器、厂商、网络环境等特征。

设备ID: 通过分析崩溃的设备id是否相同,可以用于判断是否单设备重复崩溃上报异

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值