ANR定义与分类
ANR(Application Not Responding):应用程序无响应,是Android中AMS与WMS监测应用响应超时的表现;
我们应用开发中常见的ANR主要有如下几类:
KeyDispatchTimeout
1:KeyDispatchTimeout(5 seconds) –主要类型
按键或触摸事件在特定时间内无响应
BroadcastTimeout
2:BroadcastTimeout(10 seconds)
BroadcastReceiver在特定时间内无法处理完成
ServiceTimeout
3:ServiceTimeout(20 seconds) –小概率类型
Service在特定的时间内无法处理完成
ANR的定位与分析
当anr问题发生时,一般会在logcat中有所体现,但是log中提供的信息太多,虽然最后都能找得到,但是过程还是比较痛苦滴。在这里,我给大家介绍一个简单的方法。
anr发生之后,系统会在 data/anr/ 目录下生成traces文件,通过分析这个文件,我们可以轻松明确anr发生的原因。
在这里我们先模拟一个anr场景:
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Thread.sleep(10000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this,"点我你就发了", Toast.LENGTH_SHORT).show();
}
});
此处就是定义了一个按钮,在点击它的时候我们让它沉睡一万年,当我们点击它的之后,活几秒钟之后会出现anr弹窗:
通过如下命令得到ANR trace文件:
adb pull /data/anr/traces.txt ./
然后我们在txt编辑器中打开这个文件:
//显示进程id、ANR发生时间点、ANR发生进程包名
----- pid 28956 at 2018-06-28 13:42:56 -----
Cmd line: com.hs.demo
//一些GC等object信息,通常可以忽略
......
//ANR方法堆栈打印信息!重点!
DALVIK THREADS (14):
"Signal Catcher" daemon prio=5 tid=3 Runnable
| group="system" sCount=0 dsCount=0 flags=0 obj=0x13e800e8 self=0x73a285ca00
| sysTid=28962 nice=0 cgrp=default sched=0/0 handle=0x73980cf4f0
| state=R schedstat=( 8716147 30728 4 ) utm=0 stm=0 core=4 HZ=100
| stack=0x7397fd5000-0x7397fd7000 stackSize=1005KB
| held mutexes= "mutator lock"(shared held)
native: #00 pc 0000000000398598 /system/lib64/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiP12BacktraceMapPKcPNS_9ArtMethodEPv+212)
native: #01 pc 000000000045f288 /system/lib64/libart.so (_ZNK3art6Thread9DumpStackERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEEbP12BacktraceMapb+348)
native: #02 pc 0000000000476a5c /system/lib64/libart.so (_ZN3art14DumpCheckpoint3RunEPNS_6ThreadE+880)
native: #03 pc 000000000046f438 /system/lib64/libart.so (_ZN3art10ThreadList13RunCheckpointEPNS_7ClosureES2_+476)
native: #04 pc 000000000046ee48 /system/lib64/libart.so (_ZN3art10ThreadList4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEEb+796)
native: #05 pc 000000000046e9e8 /system/lib64/libart.so (_ZN3art10ThreadList14DumpForSigQuitERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+920)
native: #06 pc 0000000000443754 /system/lib64/libart.so (_ZN3art7Runtime14DumpForSigQuitERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+196)
native: #07 pc 000000000044d1d4 /system/lib64/libart.so (_ZN3art13SignalCatcher13HandleSigQuitEv+1676)
native: #08 pc 000000000044c014 /system/lib64/libart.so (_ZN3art13SignalCatcher3RunEPv+356)
native: #09 pc 0000000000066760 /system/lib64/libc.so (_ZL15__pthread_startPv+36)
native: #10 pc 000000000001ee24 /system/lib64/libc.so (__start_thread+68)
(no managed stack frames)
//真正导致ANR的问题点,可以发现是onClick中有sleep导致。
"main" prio=5 tid=1 Sleeping
| group="main" sCount=1 dsCount=0 flags=1 obj=0x72d6fbb0 self=0x73a28a3a00
| sysTid=28956 nice=-10 cgrp=default sched=0/0 handle=0x73a762f9b0
| state=S schedstat=( 241148957 9436457 339 ) utm=20 stm=3 core=5 HZ=100
| stack=0x7fd6067000-0x7fd6069000 stackSize=8MB
| held mutexes=
at java.lang.Thread.sleep(Native method)
- sleeping on <0x0a9908a3> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:386)
- locked <0x0a9908a3> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:327)
at com.hs.demo.MainActivity$1.onClick(MainActivity.java:25)
at android.view.View.performClick(View.java:6291)
at android.view.View$PerformClick.run(View.java:24931)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7406)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:926)
......
//省略一些不常关注堆栈打印
......
通过分析,我们发现是因为MainActivity 里面的 onclick方法里面调用了 Thread.sleep()方法导致。