1、ANR简介与历史
1.1 什么是ANR
ANR,全称 Application Not Responding,说白了就是你的应用没能在规定时间内响应。我第一次遇到 ANR 时,屏幕上弹出一个"应用无响应"的对话框,我第一反应是手机坏了。后来才知道,这是 Android 在保护用户体验——当一个应用的主线程被堵住太久,系统就会判定它"已死"。
你想想看,用户点了个按钮,结果界面卡了十几秒没反应,换谁都得崩溃。ANR 机制就是系统用来"干掉"这种卡死应用的强制手段。
具体来说,ANR 触发条件分为四种场景:
- 输入事件超时——按键、触摸等事件在 5 秒内没被分发或处理
- 广播超时——
BroadcastReceiver的onReceive在 10 秒内没执行完 - 服务超时——
Service的onCreate/onStartCommand/onBind在 20 秒内没完成 - ContentProvider 超时——内容提供者的
query/insert/update/delete在 10 秒内没返回
我习惯把 ANR 理解为"主线程的交通瘫痪"。所有 UI 更新、事件分发、生命周期回调都在主线程上跑,一旦某个操作占住线程不放,后面的车就全堵死了。举个例子:
// 错误示范:在 BroadcastReceiver 的主线程里写数据库
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 这个操作可能超过10秒,直接引发 ANR
saveLargeDataToDatabase();
}
}
这种代码我在项目里见过太多次了。很多人觉得广播接收器是个"轻量"组件,随手就往里塞耗时逻辑。嗯,后果就是 ANR 对话框直接怼到用户脸上。
1.2 ANR的演进历史
Android 的 ANR 机制不是一天建成的。从 1.0 到 14.0,它经历了从"粗暴杀进程"到"精细诊断"的演变。我按时间线捋一下关键节点:
- Android 1.0 - 2.3(早期)
基础 ANR 机制建立。超时后弹"强制关闭"对话框,用户只能点"确定"杀掉应用。开发者的调试手段只有看 logcat 里搜ANR关键词。 - Android 3.0 - 4.4(中期)
增加了/data/anr/traces.txt的详细堆栈输出。我记得那时线上遇到 ANR,第一反应就是去拉这个文件。不过文件内容又长又乱,分析起来很痛苦。 - Android 5.0 - 7.0(Lollipop - Nougat)
引入了 StrictMode,帮开发者在开发阶段就发现主线程的磁盘 I/O、网络请求等违规操作。但说实话,StrictMode 只能防君子不能防小人,线上问题该出还是出。 - Android 8.0 - 9.0(Oreo - Pie)
这是个大转折。Android 8.0 限制了后台 Service 和隐式广播,很多第三方 SDK 的"后台保活"逻辑直接炸了。我在项目中遇到过某个推送 SDK 在后台拉活导致 ANR 飙升的案例,那段时间加班到凌晨三点排查——嗯,印象太深了。 - Android 10 - 12(Q - 12L)
ANR 对话框变成了"应用无响应"弹窗,用户可以选"继续等待"而不是只能"关闭"。同时系统开始提供更详细的 ANR 报告,包括 CPU 使用率、IO 状态、内存信息等。 - Android 13 - 14(当前)
ANR 诊断能力大幅增强。开发者选项里可以直接生成 ANR 轨迹文件,系统还会自动分析主线程的卡顿原因。我建议所有的性能工程师都把 targetSdk 升到 14,光这个诊断能力就值回升级成本。
1.3 不同版本的ANR行为变化
很多人问我:"不同 Android 版本的 ANR 到底有什么区别?" 我用一张表给你说明白:
| Android 版本 | 超时阈值 | 报告方式 | 用户交互 | 关键变化 |
|---|---|---|---|---|
| 1.0 - 2.3 | Input:5s / Bcast:10s / Svc:20s / CP:10s | logcat + traces.txt | 强制关闭对话框 | 基础机制建立 |
| 3.0 - 4.4 | 同上 | traces.txt 增加堆栈细节 | 同上 | 堆栈信息更完整 |
| 5.0 - 7.0 | 同上 | logcat + StrictMode 警告 | 同上 | 引入 StrictMode 开发辅助 |
| 8.0 - 9.0 | 同上 | 后台限制日志 + 原有报告 | 同上 | 后台 Service / 隐式广播受限 |
| 10 - 12 | 同上 | ANR 弹窗 + 详细报告(CPU/IO/内存) | 可"继续等待" | 报告内容大幅丰富 |
| 13 - 14 | 同上 | 增强轨迹分析 + 开发者诊断工具 | 同上 | ANR 轨迹文件 + 自动化分析 |
1.4 避坑指南:版本差异带来的线上问题
我在线上治理中踩过一个坑:某个 Android 9 的设备上,ANR 弹窗居然没弹出来,但 traces.txt 里确实记录了堆栈。后来查文档才发现,从 Android 8.0 开始,系统对后台应用的 ANR 弹窗做了限制——如果应用在后台且没有前台 Service,ANR 弹窗会被静默处理,只写日志。
所以我的建议是:无论 targetSdk 是多少,都必须在线上接入 ANR 监控。只靠用户反馈来发现 ANR,黄花菜都凉了。
1.5 本章知识体系
下面这张图浓缩了第一章的核心脉络。你可以把它当作 ANR 知识的地图——从定义出发,经过类型、原因、版本演进,最后落到行为变化。后面的章节都会围绕这张图展开。
这张图把 ANR 的完整知识链条串起来了。从上往下看:先搞清楚 ANR 是什么 → 再了解它在哪些场景下触发 → 接着分析根因 → 然后看不同版本怎么演化的 → 最后落实到具体行为变化。后面的 29 章,每一章都会在这个框架里往深挖。
我习惯把这张图贴在团队的 Wiki 首页,新同学来了先看一遍,再上手排查线上问题。效果比读文档好得多。