1 什么是ANR
Application Not Responding,即应用无响应。
2 ANR类型
- InputDispatching Timeout:5秒内无法响应屏幕触摸事件或盘输入事件
- BroadcastQueue Timeout:在执行前台广播( BroadcastReceiver)的 onReceive()函数时10秒没有处理完成,后台为60秒。
- Service Timeout:前台服务20秒内,后台服务在200秒内没有执行完毕。
- ContentProvider Timeout: ContentProvider的 publish在10秒内没进行完
3 造成ANR的主要原因
应用程序的响应性是由ActivityManager和WindowManager系统服务监视的
3.1 线程中存在耗时的操作
Android主线程中的操作:
- Activity的所有生命周期都是执行在主线程的.
- Service默认是执行在主线程的
- BroadcastReceiver的onReceive回调是执行在主线程的.
- 没有使用子线程的looper的Handler的handleMessage,post(Runnable)是执行在主线程的
- AsyncTask的回调中除了doInBackground,其他都是执行在主线程
- View的post(Runnable)是执行在主线程的.
3.2 CPU满负荷
CPU占用100%, 满负荷了。一般来说是方法中有频繁的文件读写或是数据库读写操作放在主线程来做了。
3.3 内存原因
如果由于内存泄露, App可使用内存所剩无几, 我们点击按钮启动一个大图片作为背景的activity, 就可能会产生ANR。
4 如何解决ANR
4.1 主线程阻塞
- 避免死锁
- 开辟单独的子线程来处理耗时阻塞事务
- 尽量避免在主线程query provider、不要滥用SharePreferences
4.2 CPU满负荷, I/O阻塞的
I/O阻塞一般来说就是文件读写或数据库操作执行在主线程了,通过开辟子线程的方式异步执行。
4.3 内存原因
- 排查内存泄露
- 增大VM内存, 使用largeHeap属性,
AndroidManifest.xml
文件中,<application>中设置android:largerHeap="true"
4.4 各大组件ANR
- 各大组件的生命周期中应避免耗时操作
- 注意BroadCastReceiver的onReceive()、后台Service和contentProvider也不要执行太长时间的任务
5 使用子线程的方式有哪些
-
Thread
这个也是Java实现多线程的方式。 有两种实现方法, 继承Thread 或 实现Runnable接口。
AsyncTask
-
HandlerThread
Android中结合Handler和Thread的一种方式.。 默认情况下Handler的handleMessage是执行在主线程的, 但是如果我给这个Handler传入了子线程的looper, handleMessage就会执行在这个子线程中的. HandlerThread正是这样的一个结合体:
// 启动一个名为new_thread的子线程 HandlerThread thread = new HandlerThread("new_thread"); thread.start(); // 取new_thread赋值给ServiceHandler private ServiceHandler mServiceHandler; mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // 此时handleMessage是运行在new_thread这个子线程中了. } }
-
IntentService
Service是运行在主线程的, 然而IntentService是运行在子线程的.
实际上IntentService就是实现了一个HandlerThread + ServiceHandler的模式.