1 ANR简介
ANR,全称是Application Not Responding,即应用程序无响应(不是Activity无响应)。当App在特定时间内无法响应屏幕触摸或键盘输入事件,或者特定事件没有处理完毕,就会发生ANR。
2 深入理解ANR:
2.1 特定时间:
InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件;
BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒;
Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕;
ContentProvider Timeout :ContentProvider的publish在10s内没进行完;
2.2 经常发生ANR的场景:
(1): 应用程序UI线程存在耗时操作, 如UI线程进行网络请求, 数据库操作或者文件操作, 这些耗时操作的情况都可能会导致UI线程无法及时处理用户的输入,导致ANR产生。
例如,这是一个主线程执行耗时操作的log:
(2):UI线程等待子线程释放一个锁,从而无法处理用户的请求输入;
(3):耗时操作的动画需要大量的计算工作, 导致CPU的负荷很重。
3. 如何避免ANR的发生:
尽量避免在主线程(UI线程)中作耗时操作。或者说,耗时操作尽可能在子线程中进行,而UI的更新一定得在主线程中(UI线程)进行。
4. ANR的分析方法:
主要考虑主线程的执行代码:
- 应用在主线程上非常缓慢地执行涉及 I/O 的操作。
- 应用在主线程上进行长时间的计算。
- 主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。
- 主线程处于阻塞状态,为发生在另一个线程上的长操作等待同步的块。
- 主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。
分析方法:
4.1 通过log来分析:
用logcat可以清晰的看到ANR发生的时机(见“5 ANR举例”);
4.2 查看traces.txt:
ANR发生,通常,系统会将相关信息写入到traces.txt文件中,即“/data/anr/traces.txt”文件。我们可以通过分析这个文件,从而定位ANR发生时的场景;
adb root
adb shell ls /data/anr
adb pull /data/anr/traces.txt
4.3 通过traceview等工具来分析:
入下图(traceview):
分析:
上图中,耗时代码都在子线程AsyncTask中进行,所以不会发生ANR。 如果main中有大面积的红色区域块,说明在主线程中有耗时操作,就有ke能发生ANR。
5 ANR举例:
分析如下代码:
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
分析:
在主线程中,用sleep来模拟耗时操作。
运行程序log如下:
2014-10-12 11:12:23.612 3105-3180/system_process E/ActivityManager: ANR in com.example.app1 (com.example.app1/.MainActivity)
PID: 19534
Reason: Input dispatching timed out(com.example.app1/com.example.app1.MainActivity, Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 2. Wait queue head age: 8602.5ms.)
Parent: com.example.app1/.MainActivity
Load: 7.01 / 6.89 / 6.74
CPU usage from 0ms to 6142ms later (2014-10-12 11:12:17.718 to 2014-10-12 11:12:23.811):
16% 3105/system_server: 7.9% user + 8.1% kernel / faults: 6549 minor
0.3% 2779/media.codec: 0.2% user + 0% kernel / faults: 35716 minor
10% 763/surfaceflinger: 8.2% user + 2.6% kernel / faults: 419 minor
...
0.1% 27263/kworker/4:2: 0% user + 0.1% kernel
0.1% 27743/kworker/0:0: 0% user + 0.1% kernel
15% TOTAL: 10% user + 5.4% kernel + 0.1% iowait + 0.2% irq + 0% softirq
说明:
很明显,发生了ANR,而且,在log中,也能看到具体发生ANR的类名,方法名,进程ID,原因等信息。该例中的这些信息是:
ANR in com.example.app1 (com.example.app1/.MainActivity)
PID: 19534
Reason: Input dispatching timed out
6 ANR源码调用:
只有发生ANR,那么,AppNotRespondingDialog.show();就会被调用:
AppNotRespondingDialog.show();
在ActivityManagerService,有如下代码:
case SHOW_NOT_RESPONDING_MSG: {
......
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
mContext, proc,
(ActivityRecord)data.get("activity"));
d.show();
proc.anrDialog = d;
......
}