首先我们要理解关于Android的ANR的一些理论知识:
1.什么是Android的ANR?
ANR顾名思义就是Application Not Response,即应用无响应。
2.ANR分为三类:
KeyDispatchTimeOut(5 秒)
BroadcastTimeOut(10 秒)
ServiceTimeOut(20 秒)
3.三类ANR分别发生的原因:
KeyDispatchTimeOut:
按键或触摸事件在5秒内无法完成,即从按键分发给app开始计时,如果此事件在5秒内无法完成就会报出此类ANR提示。
此时超时的原因一般有两种:1.当前的事件没有来得及处理,(UI线程正在处理前一个事件,没有及时完成或者looper因为某些原因被阻塞了);2.当前的事件正在处理,但没有及时完成。
BroadcastTimeOut:
BroadcastReceiver在10秒内无法处理完成相关逻辑
ServiceTimeOut:
这种是小概率事件,Service在20秒内没有执行完成相关逻辑
4.如何避免ANR的发生呢?
这里以KeyDispatchTimeOut为例:
(1)UI线程尽量做UI相关的操作。
(2)耗时的操作(比如数据库、IO流操作、连接网络或者别的有可能阻碍UI线程的操作)放入单独的线程进行处理。
(3)尽量用Handler来处理UI线程与别的线程之间的通信。
5.补充说明下什么是UI线程:
UI线程主要包括以下:
(1)Activity的生命周期的方法、onKeyDown()、onClick()。
(2)AsyncTask:onPreExecute()、onProgressUpdate()、onPostExecute()、onCancel()等等
(3)Mainthead Handler: handleMessage()、 post(Runnable) 等等
(4)其他的
了解了相关ANR的理论,现在就要具体实践了。
1.如何分析ANR?
首先我们看log:
04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}. 5009.8ms since event, 5009.5ms since waitstarted
04-01 13:12:11.572 I/WindowManager( 220): Input event dispatching timedout sending tocom.android.email/com.android.email.activity.SplitScreenActivity
04-01 13:12:14.123 I/Process( 220): Sending signal. PID: 21404 SIG: 3---发生ANR的时间和生成trace.txt的时间
04-01 13:12:14.123 I/dalvikvm(21404):threadid=4: reacting to signal 3
04-01 13:12:15.872 E/ActivityManager( 220): ANR in com.android.email(com.android.email/.activity.SplitScreenActivity)
04-01 13:12:15.872 E/ActivityManager( 220): Reason:keyDispatchingTimedOut
04-01 13:12:15.872 E/ActivityManager( 220): Load: 8.68 / 8.37 / 8.53
04-01 13:12:15.872 E/ActivityManager( 220): CPUusage from 4361ms to 699ms ago ----CPU在ANR发生前的使用情况
04-01 13:12:15.872 E/ActivityManager( 220): 5.5%21404/com.android.email: 1.3% user + 4.1% kernel / faults: 10 minor
04-01 13:12:15.872 E/ActivityManager( 220): 4.3%220/system_server: 2.7% user + 1.5% kernel / faults: 11 minor 2 major
04-01 13:12:15.872 E/ActivityManager( 220): 0.9%52/spi_qsd.0: 0% user + 0.9% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 0.5%65/irq/170-cyttsp-: 0% user + 0.5% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 0.5%296/com.android.systemui: 0.5% user + 0% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait
04-01 13:12:15.872 E/ActivityManager( 220): CPUusage from 3697ms to 4223ms later:-- ANR后CPU的使用量
04-01 13:12:15.872 E/ActivityManager( 220): 25%21404/com.android.email: 25% user + 0% kernel / faults: 191 minor
04-01 13:12:15.872 E/ActivityManager( 220): 16% 21603/__eas(par.hakan: 16% user + 0% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 7.2% 21406/GC: 7.2% user + 0% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 1.8% 21409/Compiler: 1.8% user + 0% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 5.5%220/system_server: 0% user + 5.5% kernel / faults: 1 minor
04-01 13:12:15.872 E/ActivityManager( 220): 5.5% 263/InputDispatcher: 0% user + 5.5% kernel
04-01 13:12:15.872 E/ActivityManager( 220): 32%TOTAL: 28% user + 3.7% kernel
从LOG可以看出ANR的类型,CPU的使用情况,如果CPU使用量接近100%,说明当前设备很忙,有可能是CPU饥饿导致了ANR
如果CPU使用量很少,说明主线程被BLOCK了
如果IOwait很高,说明ANR有可能是主线程在进行I/O操作造成的
除了看LOG,解决ANR还得需要trace.txt文件,
如何获取呢?可以用如下命令获取
$chmod 777 /data/anr
$rm /data/anr/traces.txt
$ps
$kill -3 PID
adbpull data/anr/traces.txt ./mytraces.txt
从trace.txt文件,看到最多的是如下的信息:
-----pid 21404 at 2011-04-01 13:12:14 -----
Cmdline: com.android.email
DALVIK THREADS:
(mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1NATIVE
| group="main" sCount=1 dsCount=0obj=0x2aad2248 self=0xcf70
| sysTid=21404 nice=0 sched=0/0cgrp=[fopen-error:2] handle=1876218976
atandroid.os.MessageQueue.nativePollOnce(Native Method)
atandroid.os.MessageQueue.next(MessageQueue.java:119)
atandroid.os.Looper.loop(Looper.java:110)
at android.app.ActivityThread.main(ActivityThread.java:3688)
at java.lang.reflect.Method.invokeNative(Native Method)
atjava.lang.reflect.Method.invoke(Method.java:507)
atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
at dalvik.system.NativeStart.main(Native Method)
说明主线程在等待下条消息进入消息队列
2.总结出如何解决ANR的一般步骤:
(1)首先分析log
(2)从trace.txt文件中查看调用track
(3)仔细查看ANR的成因(iowait?block?memoryleak?)
(4)结合分析结果,查看相关代码,找出出现问题的代码并修改验证。