ANR全名Application Not Responding, 也就是"应用无响应". 当操作在一段时间内系统无法处理时, 系统层面会弹出上图那样的ANR对话框.
产生ANR原因
在Android里, App的响应能力是由Activity Manager和Window Manager系统服务来监控的. 通常在如下两种情况下会弹出ANR对话框:
- 5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等).
- BroadcastReceiver在10s内无法结束.
造成以上两种情况的首要原因就是在主线程(UI线程)里面做了太多的阻塞耗时操作, 例如文件读写, 数据库读写, 网络查询等等.
如何避免ANR
知道了ANR产生的原因, 那么想要避免ANR, 也就很简单了, 就一条规则:
不要在主线程(UI线程)里面做繁重的操作.
可能产生ANR的条件
- 普通阻塞导致的ANR
- CPU满负荷,这时候一般会在 trace中最后一句看到(100%TOTAL: 5.9% user + 4.1% kernel + 89% iowait)
- 内存原因(其实内存原因有可能会导致ANR, 例如如果由于内存泄露, App可使用内存所剩无几, 我们点击按钮启动一个大图片作为背景的activity, 就可能会产生ANR)
ANR的处理
针对三种不同的情况, 一般的处理情况如下
- 主线程阻塞的
开辟单独的子线程来处理耗时阻塞事务.
- CPU满负荷, I/O阻塞的
I/O阻塞一般来说就是文件读写或数据库操作执行在主线程了, 也可以通过开辟子线程的方式异步执行.
- 内存不够用的
增大VM内存, 使用largeHeap属性, 排查内存泄露(这个在内存优化那篇细说吧)等.
知识点
哪些地方是执行在主线程的
- Activity的所有生命周期回调都是执行在主线程的.
- Service默认是执行在主线程的.
- BroadcastReceiver的onReceive回调是执行在主线程的.
- 没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.
- AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.
- View的post(Runnable)是执行在主线程的.
使用子线程的方式有哪些
- 启Thread方式(继承Thread、实现Runnable接口)
- 使用AsyncTask
- HandlerThread
- IntentService
- Loader