Android ANR 触发原理通俗详解:应用卡顿的幕后机制

218 阅读3分钟

一、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?工厂管理思维

  1. 耗时任务放后台:用 Service、WorkManager 处理耗时操作,不阻塞主线程。
  2. 控制任务时长:前台服务 20 秒内完成初始化,广播 10 秒内结束。
  3. 优化 IO 操作:避免在主线程读写文件、访问数据库。
  4. 监控工具:用 TraceView、Systrace 定位卡顿点,如adb shell dumpsys activity anr获取 ANR 日志。

七、总结:ANR 是系统的 "健康报警器"

ANR 本质是系统对应用的保护机制,当发现主线程长时间阻塞时,通过弹窗提醒用户并尝试恢复系统响应。理解其触发原理后,开发者可通过优化任务调度、避免主线程阻塞,从源头减少 ANR 发生,让应用如丝般流畅。