ANR
什么是 ANR
Application Not Responding,意思就是程序未响应。如果一个应用无法响应用户的交互,系统就会弹出一个 ANR 对话框。
出现场景
- InputDispatching Timeout:在 5 秒内没有响应屏幕触摸事件或键盘输入事件
- BroadcastQueue Timeout:在执行前台广播(BroadcastReceiver)的
onReceive()
函数时 10 秒没有处理完成,后台为 60 秒 - Service Timeout:前台服务 20 秒内,后台服务在 200 秒内没有执行完毕
- ContentProvider Timeout:ContentProvider 的 publish 在 10 秒内没有进行完
主线程被 I/O 操作(从 4.0 之后网络 I/O 不允许在主线程中)阻塞、或是主线程中存在耗时或是错误的计算(比如 Thread.wait() 或者 Thread.sleep() 等)
Android 系统中,ActivityManagerService(AMS)和 WindowManagerService(WMS)会检测 App 的响应时间,如果 App 在特定时间无法响应屏幕触摸或键盘输入事件,或者特定事件没有处理完毕,就会出现 ANR
如何避免
将 I/O 操作在工作线程来处理,减少其他耗时操作和错误操作。
- 使用 AsyncTask 处理耗时 IO 操作
- 使用 Thread 或者 HandlerThread 时,调用
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
设置优先级,否则仍会降低程序响应,因为默认 Thread 的优先级和主线程相同。 - 使用 Handler 处理工作线程结果,而不是使用
Thread.wait()
或者Thread.sleep()
来阻塞主线程。 - Activity 的
onCreate()
和onResume()
中尽量避免耗时的代码 - BroadcastReceiver 中
onReceive()
中也要尽量减少耗时代码,建议使用 IntentService 处理
如何定位
通过查看/data/anr/traces.txt
,最新的 ANR 信息在最开始部分。
原理流程总结
Service Timeout
- Service 在创建之前会延迟发送一个消息,而这个消息就是 ANR 的起源
- Service 创建完毕,在规定的时间之内执行完毕
onCreate()
方法就移除这个消息,就不会产生 ANR 了; - 在规定时间之内没有完成
onCreate()
的调用,消息被执行,ANR 发生。