1. ANR概念与分类
1.1 什么是ANR?
ANR,全称是 Application Not Responding。说白了,就是你的App卡死了,系统实在等不下去了,直接弹个对话框——"要关闭吗?"。
我记得刚入行那会儿,第一次见到这个对话框还以为是手机中毒了。后来才明白,这是Android系统在保护用户体验。系统规定了几种超时阈值,一旦主线程在规定时间内没有完成特定操作,立马触发ANR。
核心就一句话:主线程被阻塞了,而且阻塞时间超过了系统容忍的极限。
ANR的本质:主线程无法及时处理下一个消息,导致系统判定"无响应"。
为什么会这样?你想想看,主线程要同时处理用户点击、界面绘制、广播接收、Service启动……一旦某个任务占用了太久,后续所有任务都得排队。用户等得不耐烦了,系统也觉得不对劲,ANR就来了。
1.2 四大ANR类型与触发条件
ANR不是铁板一块,它分四种类型。每种类型的触发场景和超时阈值都不一样。我在项目里几乎都踩过一遍,一个一个跟你聊。
1.2.1 输入事件ANR
这是最常见的ANR类型。用户点了一下屏幕,系统把触摸事件分发给App,但App5秒内没有处理完成——直接弹窗。
触发条件:
- 输入事件(按键、触摸、轨迹球)分发后,5秒内没有处理完
- 或上一个输入事件处理超过5秒,导致后续事件被积压
我的经验:我遇到过一个案例,用户在列表快速滑动时触发大量异步回调,回调里直接更新UI,结果主线程被活活拖死。这就是典型的输入ANR。
1.2.2 广播ANR
广播分两种:前台广播和后台广播。阈值不一样,你别搞混了。
| 广播类型 | 超时阈值 | 典型场景 |
|---|---|---|
| 前台广播 | 10秒 | 高优先级、用户可感知的广播 |
| 后台广播 | 60秒 | 普通广播、系统广播 |
广播ANR的坑在哪里?很多人以为广播是异步的,不卡主线程。其实broadcast receiver的 onReceive() 方法默认就在主线程执行。你在里面做网络请求、数据库写入、或者循环解析JSON……嗯,10秒很快的。
避坑指南:我曾经在 onReceive() 里直接调了一个HTTP接口,结果网络延迟到8秒,前台广播直接就挂了。记住:广播里不要做耗时操作,用 goAsync() 或者扔给Service处理。
1.2.3 服务ANR
Service ANR有两个触发点:
- 前台服务:
onCreate()、onStartCommand()、onBind()等生命周期方法超过20秒 - 后台服务: 超过200秒
这里有个细节你注意一下:前台服务的20秒阈值,是从Android 8.0开始收紧的。早期版本是200秒统一处理。Google是铁了心要治后台滥用。
我有个血泪教训:项目里有一个上传日志的服务,每次启动时先把本地数据库里两个月的数据全读出来再压缩上传。结果一次上传前数据量爆炸,直接卡了30秒……前台服务ANR弹窗,用户直接卸载了App。
1.2.4 ContentProvider ANR
这一种相对少见,但一旦出现就很棘手。ContentProvider ANR发生在进程间通信时,比如一个App通过ContentResolver查询另一个App的ContentProvider,对方如果在规定时间内没有返回结果,查询方就会ANR。
触发条件:
- ContentProvider的
query()、insert()、update()、delete()方法超过30秒 - 注意:这30秒是包含在Binder线程池里的,不是主线程,但如果调用方在主线程等待,照样卡死
实际场景:我遇到过三方SDK通过ContentProvider获取设备信息,结果那个Provider的实现里做了网络请求。查询方主线程调用,直接卡死5秒以上——虽然没到30秒阈值,但是又叠加了输入事件5秒阈值,照样ANR。
1.3 ANR知识体系总览
下面这张图把四种ANR类型和它们的核心参数画在了一起。你可以把它当作快速参考。
1.4 四种类型对比速查表
| ANR类型 | 超时阈值 | 执行线程 | 常见触发场景 |
|---|---|---|---|
| 输入事件 | 5秒 | 主线程 | UI更新阻塞、布局过于复杂、动画卡顿 |
| 广播(前台) | 10秒 | 主线程(onReceive) | 网络请求、数据库写入、JSON解析 |
| 广播(后台) | 60秒 | 主线程(onReceive) | 同上,但阈值宽松 |
| 服务(前台) | 20秒 | 主线程(生命周期) | 启动时加载大文件、加密运算 |
| 服务(后台) | 200秒 | 主线程(生命周期) | 同上,但阈值宽松 |
| ContentProvider | 30秒 | Binder线程池 | Provider实现耗时操作、网络请求 |
再一次强调:阈值只是"系统弹窗"的底线。用户体验的容忍度远小于这些数字。真实场景中,卡顿超过500毫秒用户就能感知,超过2秒就可能流失。别等ANR再动手,提前预防才是王道。
1.5 我的一点心得
ANR问题最难的不是修复,而是定位。尤其是线上ANR,复现条件千奇百怪。我最早遇到一个广播ANR,只在用户手机安装了很多应用并且低电量时才触发。后来发现是onReceive()里做了包名列表遍历——用户应用越多,耗时越长。
所以我把这个章节放在第一位,就是想让你先建立起"ANR识别"的直觉。遇到卡顿,第一时间想想:这属于哪种类型的ANR?阈值是多少?是不是在主线程?
有了这个基础,后面听定位工具、分析堆栈、解决方案的时候,才不会跑偏。