1. ANR 概述

1.1 什么是 ANR

ANR 的全称是 Application Not Responding,也就是「应用无响应」。说白了,你的 App 在主线程里干了太多活,系统等不及了,就会弹出一个对话框告诉用户:「这个应用没有响应,你要不要关掉它?」。

我刚开始做 Android 开发时,第一次遇到 ANR 完全懵了。当时我正在调试一个图片上传功能,点了按钮后界面直接卡死,过了几秒系统弹了个对话框。我还以为是手机死机了……后来才知道,原来是我在 主线程 里直接做了网络上传。

为什么会这样?Android 系统为了保障用户体验,给主线程设定了一个「容忍极限」。一旦主线程在规定时间内没有处理完该做的事,系统就会判定为 ANR。你想想看,如果你点了一个按钮,等了 10 秒都没反应,你是不是也想关掉这个 App?

核心要点:ANR 的本质是主线程被阻塞,导致无法及时处理用户交互或系统请求。
ANR 概述知识体系 ANR 概述 什么是 ANR ANR 的类型 触发条件与超时时间 输入事件 (5s) 广播 (10s / 60s) 服务 (20s) ContentProvider (10s) ANR(Application Not Responding) Android 系统检测到应用主线程阻塞超过阈值时, 会弹出 ANR 对话框,提示用户「应用无响应」。

1.2 ANR 的类型

Android 系统定义了四种 ANR 场景。每种场景的触发方式和超时时间都不一样。我在项目中基本都碰过一遍,印象太深了。

  • 输入事件 ANR —— 用户触摸或按键后,系统在 5 秒内没能把事件分发到 Activity 或 View 并处理完成。我记得有一次排查一个线上问题,用户反馈「点登录按钮没反应」,看了 traces 文件才发现是主线程在等一个锁,锁被后台线程占着不放。
  • 广播 ANR —— BroadcastReceiver 的 onReceive() 方法执行时间过长。前台广播超时 10 秒,后台广播超时 60 秒。我踩过一个坑:在 onReceive() 里直接调了 SharedPreferences 的繁重写入,数据量大时直接卡死。
  • 服务 ANR —— Service 的生命周期方法(如 onCreate()、onStartCommand() 等)超过 20 秒没执行完。说实话,这个在普通 App 里不太常见,但如果你在服务里做了大批量数据库操作,就很容易触发。
  • ContentProvider ANR —— ContentProvider 的操作超过 10 秒没响应。我在项目中就遇到过:另一个 App 通过 ContentResolver 查询我们的 ContentProvider,结果我们在 query() 里做了复杂的跨进程数据合并,直接 ANR。
个人小习惯:我每次写 BroadcastReceiver 和 Service 时,都会在入口方法里加一行日志,记录开始时间。如果发现执行超过 2 秒,我就会考虑用 goAsync() 或者直接扔到 WorkManager 里去做。

1.3 触发条件与系统超时时间

ANR 的触发条件,说到底只有一条:主线程被阻塞,导致无法及时处理下一个消息。但具体「多久算不及时」,系统针对不同场景有不同阈值。

ANR 类型 触发场景 超时时间
输入事件 ANR 按键 / 触摸事件未在阈值内处理完成 5 秒
广播 ANR(前台) BroadcastReceiver.onReceive() 执行超时 10 秒
广播 ANR(后台) BroadcastReceiver.onReceive() 执行超时 60 秒
服务 ANR Service 生命周期方法执行超时 20 秒
ContentProvider ANR ContentProvider 操作(query / insert / update / delete)超时 10 秒

除了阈值,还有几个常见的「帮凶」:

  • 主线程直接做网络请求 —— 这是最经典的 ANR 原因,没有之一。
  • 主线程持有锁,被其他线程长时间占用 —— 我遇到过死锁导致的 ANR,两个线程互相等对方的锁,主线程也插不进去。
  • IPC 调用等待 —— 比如主线程跨进程调用 ContentProvider 或 Service,对方响应慢就会连带卡住你。
  • 系统负载过高 —— CPU 被占满,主线程抢不到时间片。这种情况虽然少见,但在低端机上确实会发生。
我曾经踩过的坑:有一次我在 Activity.onCreate() 里直接调用了 PackageManager.queryIntentActivities(),这个方法在部分系统版本上会触发跨进程通信,如果系统服务繁忙,主线程就会卡住。后来我把这个调用移到了异步线程,问题瞬间消失。
一句话总结:ANR 是 Android 系统给主线程画的一条红线。只要你在主线程里做了任何可能超过阈值的事,系统就会翻脸。理解这四种 ANR 类型和它们的超时时间,是后续优化工作的基础。
一个小建议:刚接触 ANR 的同学,可以先用 adb shell dumpsys dropbox --print data_app_anr 拉取设备上的 ANR 日志来看。读上三五份 traces 文件,你就能直观感受到 ANR 长什么样了。