一、ANR 是什么?应用的 "罢工警告"
ANR(Application Not Responding)即应用无响应,当系统检测到应用在规定时间内未完成关键任务时,会弹出 "应用无响应" 对话框。这就像工厂生产线卡顿,管理员(系统)发现工人(应用)没按时完成任务,发出警告。
二、ANR 的四大触发场景与超时时间
| 场景 | 前台超时时间 | 后台超时时间 | 典型案例 |
|---|---|---|---|
| Service 超时 | 20 秒 | 200 秒 | 下载服务在前台超过 20 秒未完成启动 |
| 广播 (Broadcast) 超时 | 10 秒 | 60 秒 | 前台广播处理超过 10 秒未结束 |
| ContentProvider 超时 | 10 秒 | - | 应用启动时 ContentProvider 注册超过 10 秒未完成 |
| 输入事件 (Input) 超时 | 5 秒 | - | 触摸事件 5 秒内未被处理 |
三、ANR 的核心流程:埋炸弹、拆炸弹与爆炸
以 Service 超时为例,理解 ANR 的触发机制,其他场景原理类似:
1. 埋炸弹:系统设置 "超时闹钟"
当启动一个 Service 时,系统会发送一条延迟消息(SERVICE_TIMEOUT_MSG),相当于设置一个闹钟:
-
前台服务:20 秒后响铃(SERVICE_TIMEOUT = 20000ms);
-
后台服务:200 秒后响铃(SERVICE_BACKGROUND_TIMEOUT = 200000ms)。
java
// 代码示例:启动服务时埋下炸弹
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
long now = SystemClock.uptimeMillis();
// 发送延迟消息,超时未拆除则触发ANR
mAm.mHandler.sendMessageAtTime(msg,
proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+SERVICE_BACKGROUND_TIMEOUT));
}
2. 拆炸弹:服务完成时取消闹钟
当服务的 onCreate () 方法执行完毕,系统会移除超时消息,相当于提前取消闹钟:
java
// 服务创建完成后拆炸弹
ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, ...);
3. 引爆炸弹:超时未拆弹触发 ANR
如果服务在超时前未完成启动,闹钟响起(SERVICE_TIMEOUT_MSG 被处理),系统判定 ANR:
java
// 超时处理逻辑
void serviceTimeout(ProcessRecord proc) {
// 检查是否有服务超时
if (timeout != null) {
mAm.appNotResponding(proc, null, null, false, "executing service " + timeout.shortName);
}
}
此时系统会收集日志,并弹出 ANR 对话框,用户可选择等待或强制关闭应用。
四、各场景 ANR 触发细节对比
1. 广播 (Broadcast) 超时
- 埋炸弹:处理有序广播时,为每个接收者设置超时(前台 10 秒,后台 60 秒)。
- 拆炸弹:广播处理完成后移除超时消息。
- 特殊点:静态注册的广播会受 SharedPreferences 同步影响,若 SP 有未完成任务,广播超时检测会等待其完成。
2. ContentProvider 超时
- 埋炸弹:应用启动时注册 Provider,10 秒内未完成则触发。
- 引爆炸弹:超时后直接杀死进程,不弹出对话框(因属于应用启动阶段)。
3. 输入事件 (Input) 超时
- 触发条件:触摸 / 按键事件 5 秒内未被处理,如主线程被阻塞无法响应输入。
- 典型场景:主线程执行耗时运算,导致触摸事件堆积。
五、ANR 的幕后黑手:主线程阻塞
所有 ANR 的根本原因都是主线程(UI 线程)被阻塞,无法及时处理系统事件。例如:
- Service 超时:在 onCreate () 中执行网络请求;
- 广播超时:在 onReceive () 中处理大文件读写;
- 输入超时:在主线程进行复杂计算。
六、如何避免 ANR?工厂管理思维
- 耗时任务放后台:用 Service、WorkManager 处理耗时操作,不阻塞主线程。
- 控制任务时长:前台服务 20 秒内完成初始化,广播 10 秒内结束。
- 优化 IO 操作:避免在主线程读写文件、访问数据库。
- 监控工具:用 TraceView、Systrace 定位卡顿点,如
adb shell dumpsys activity anr获取 ANR 日志。
七、总结:ANR 是系统的 "健康报警器"
ANR 本质是系统对应用的保护机制,当发现主线程长时间阻塞时,通过弹窗提醒用户并尝试恢复系统响应。理解其触发原理后,开发者可通过优化任务调度、避免主线程阻塞,从源头减少 ANR 发生,让应用如丝般流畅。