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 秒内没返回
核心本质:主线程(UI线程)的消息循环被阻塞,导致无法处理下一个消息。

我习惯把 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.0 到 14.0 基本没变过,但系统判断 ANR 的"精准度"和"报告粒度"一直在提升。换句话说,ANR 没变少,但你能查到的信息变多了——这对线上治理是大利好。

1.4 避坑指南:版本差异带来的线上问题

我在线上治理中踩过一个坑:某个 Android 9 的设备上,ANR 弹窗居然没弹出来,但 traces.txt 里确实记录了堆栈。后来查文档才发现,从 Android 8.0 开始,系统对后台应用的 ANR 弹窗做了限制——如果应用在后台且没有前台 Service,ANR 弹窗会被静默处理,只写日志。

注意:不要以为"没弹 ANR 对话框"就等于"没有 ANR"。后台 ANR 是不会弹窗的,但你的应用可能已经被系统标记为"不健康",进而影响后续的启动速度、任务调度等。

所以我的建议是:无论 targetSdk 是多少,都必须在线上接入 ANR 监控。只靠用户反馈来发现 ANR,黄花菜都凉了。

1.5 本章知识体系

下面这张图浓缩了第一章的核心脉络。你可以把它当作 ANR 知识的地图——从定义出发,经过类型、原因、版本演进,最后落到行为变化。后面的章节都会围绕这张图展开。

ANR 知识体系与版本演进 ANR 定义 应用无响应 四大触发类型 Input · Broadcast · Service · CP 核心原因 主线程阻塞 · 耗时操作 · Binder 等待 版本演进 1.0 → 4.0 → 7.0 → 10.0 → 14.0 行为变化 超时时间 · 报告方式 · 处理策略 超时阈值参考 Input 事件:5 秒 Broadcast:10 秒 Service:20 秒 ContentProvider:10 秒 从定义到行为变化,ANR 的每个环节都有对应的治理手段 后续章节将逐一深入每个模块

这张图把 ANR 的完整知识链条串起来了。从上往下看:先搞清楚 ANR 是什么 → 再了解它在哪些场景下触发 → 接着分析根因 → 然后看不同版本怎么演化的 → 最后落实到具体行为变化。后面的 29 章,每一章都会在这个框架里往深挖。

我习惯把这张图贴在团队的 Wiki 首页,新同学来了先看一遍,再上手排查线上问题。效果比读文档好得多。