Android 如何分析解决Android ANR
一 、什么是ANR
ANR: Application Not Responding,即应用无响应
二、ANR的类型
ANR一般有三种类型:
1:KeyDispatchTimeout(5 seconds) --主要类型
按键或触摸事件在特定时间内无响应
2:BroadcastTimeout(10 seconds)
BroadcastReceiver在特定时间内无法处理完成
3:ServiceTimeout(20 seconds) --小概率类型
Service在特定的时间内无法处理完成
三、KeyDispatchTimeout
Akey or touch event was not dispatched within the specified time(按键或触摸事件在特定时间内无响应)
具体的超时时间的定义在framework下的
ActivityManagerService.java
//How long we wait until we timeout on key dispatching.
staticfinal int KEY_DISPATCHING_TIMEOUT = 5*1000
四、为什么会超时呢?
超时时间的计数一般是从按键分发给app开始。超时的原因一般有两种:
(1)当前的事件没有机会得到处理(即UI线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
(2)当前的事件正在处理,但没有及时完成
五、如何避免KeyDispatchTimeout
1:UI线程尽量只做跟UI相关的工作
2:耗时的工作(比如数据库操作,I/O,连接网络或者别的有可能阻碍UI线程的操作)把它放入单独的线程处理
3:尽量用Handler来处理UIthread和别的thread之间的交互
六、UI线程
说了那么多的UI线程,那么哪些属于UI线程呢?
UI线程主要包括如下:
1.Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc
2.AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc
3.Mainthread handler: handleMessage(), post*(runnable r), etc
4.other
七:如何去分析ANR 总结观察log文件的基本步骤
1.从log中搜索“ANR in”或“am_anr”,会找到ANR发生的log,该行会包含了ANR的时间、进程、是何种ANR等信息
2.如果是ForceClosed 和其它异常退出信息,则搜索"Fatal" 关键词, 快速定位到关键事件信息 。
3.定位到关键事件信息后 , 如果信息不够明确的,再去搜索应用程序包的虚拟机信息 ,查看具体的进程和线程跟踪的日志,来定位到代码 。
例:打开log文件 , 由于是ANR错误,因此搜索"ANR in " , 为何要加空格呢,你加上和去掉比较一下就知道了 。 可以屏蔽掉不少保存到anr.log文件的无效信息 。
定位到关键的事件信息如下:
--------- switch to system
01-01 01:12:12.700506 359 395 W ProcessCpuTracker: Skipping unknown process pid 18163
01-01 01:12:12.703659 359 395 E ActivityManager: ANR in com.hsae.cn202sr.usb (com.hsae.cn202sr.usb/.music.MusicPlayActivity)
01-01 01:12:12.703659 359 395 E ActivityManager: PID: 902
01-01 01:12:12.703659 359 395 E ActivityManager: Reason: Input dispatching timed out (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: 5. Wait queue head age: 5622.3ms.)
01-01 01:12:12.703659 359 395 E ActivityManager: Load: 2.62 / 2.69 / 2.05
01-01 01:12:12.703659 359 395 E ActivityManager: CPU usage from 0ms to 6382ms later (2019-01-01 01:12:06.291 to 2019-01-01 01:12:12.674):
…
01-01 01:12:12.703659 359 395 E ActivityManager: 2.6% 250/media.codec: 2.6% user + 0% kernel / faults: 2 minor
01-01 01:12:12.703659 359 395 E ActivityManager: 2.6% 289/HwBinder:250_2: 2.6% user + 0% kernel
01-01 01:12:12.703659 359 395 E ActivityManager: 2.7% 259/logcatd: 0% user + 2.7% kernel
01-01 01:12:12.703659 359 395 E ActivityManager: 61% TOTAL: 28% user + 32% kernel + 0.5% iowait
在1分12秒的时候 ActivityManager 发生了如下错误:com.hsae.cn202sr.usb 包下面的MusicPlayActivity 无响应 。
原因:Reason: Input dispatching timed out
翻译:5分钟,10分钟,15分钟内的平均负载分别为:2.62 , 2.69 , 2.05
在这里我们大概知道问题是什么了,结合我们之前的操作流程,我们知道问题是在点击按钮某时候可能处理不过来按钮事件,导致超时无响应 。那么现在似乎已经可以进行工作了 。 我们知道Activity中是通过重载dispatchTouchEvent(MotionEvent ev)来处理点击屏幕事件 。 然后我们可以顺藤摸瓜,一点点分析去查找原因 。 但这样够了么 ?其实不够 , 至少我们不能准确的知道到底问题在哪儿 , 只是猜测 ,比如这个应用程序中,我就在顺藤摸瓜的时候发现了多个IO操作的地方都在主线程中,可能引起问题,但不好判断到底是哪个 ,所以我们目前掌握的信息还不够 。 于是我们再分析log文件中的traces.txt, 搜索“Dalvik Thread”关键词,快速定位到本应用程序的虚拟机信息日志,如下:
DALVIK THREADS (17):
“main” prio=5 tid=1 Native
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x732dc000 self=0xb0204000
| sysTid=902 nice=-10 cgrp=default sched=0/0 handle=0xb3a344a8
| state=S schedstat=( 20251017391 5278422276 56303 ) utm=1552 stm=473 core=3 HZ=100
| stack=0xbe0c3000-0xbe0c5000 stackSize=8MB
| held mutexes=
native: #00 pc 00049618 /system/lib/libc.so (__ioctl+8)
native: #01 pc 0001e167 /system/lib/libc.so (ioctl+38)
native: #02 pc 00040bcf /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+170)
native: #03 pc 00041589 /system/lib/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+236)
native: #04 pc 0003bae1 /system/lib/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+36)
native: #05 pc 00063023 /system/lib/libmedia.so (???)
native: #06 pc 00063d31 /system/lib/libmedia.so (android::MediaMetadataRetriever::setDataSource(int, long long, long long)+72)
native: #07 pc 00028b6d /system/lib/libmedia_jni.so (???)
native: #08 pc 005e7dcf /system/framework/arm/boot-framework.oat (Java_android_media_MediaMetadataRetriever_setDataSource__Ljava_io_FileDescriptor_2JJ+126)
at android.media.MediaMetadataRetriever.setDataSource(Native method)
at android.media.MediaMetadataRetriever.setDataSource(MediaMetadataRetriever.java:69)
at com.hsae.imxplayer.core.MusicAndoridMediaPlayer.getArtist(MusicAndoridMediaPlayer.java:168)
at com.hsae.imxplayer.core.MusicHSAEMediaPlayer.getArtist(MusicHSAEMediaPlayer.java:454)
at com.hsae.cn202sr.usb.music.core.MusicPlayService.getArtistName(MusicPlayService.java:289)
at com.hsae.cn202sr.usb.music.core.MusicPlayControl.getArtist(MusicPlayControl.java:1203)
at com.hsae.cn202sr.usb.music.core.MusicPlayService.play(MusicPlayService.java:196)
at com.hsae.cn202sr.usb.music.core.MusicPlayControl.play(MusicPlayControl.java:528)
at com.hsae.cn202sr.usb.music.core.MusicPlayControl.doPlayPause(MusicPlayControl.java:274)
at com.hsae.cn202sr.usb.music.view.impl.MusicControlImplPerformClick.run(View.java:24705)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6600)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:772)
每一段都是一个线程 ,当然我们还是看线程号为1的主线程了。通过分析发现关键问题是这样:
at com.hsae.cn202sr.usb.music.view.impl.MusicControlImpl$4.onClick(MusicControlImpl.java:367)
定位到代码:
private final OnClickListener mPlayPauseListener = new OnClickListener() {
@Override
public void onClick(View v) {
if(!AppContext.getInstance().isUsbMounted()){
PopUpUtil.getInstance().popUpRemind(Util.POP_UNMOUNT_USB);
return;
}
if (mPauseClickListener != null) {
if (msc.isPlaying()) {
mPauseClickListener.stopRotate();
} else {
mPauseClickListener.startRotate();
}
}
msc.doPlayPause();
}
};
很清楚了, msc.doPlayPause()方法之后执行时间太长的问题
推荐阅读
-
Android之ndk编译出现"undefined reference to method"解决办法
-
安卓开发学习笔记(一):如何用Android Stuidio导出apk文件?
-
Android设备获取扫码枪扫描的内容与可能遇到的问题解决
-
对微信Android版的交互协议和加密模式的进一步分析及修复方案
-
Android 7.0行为变更 FileUriExposedException解决方案 框架
-
Android 7.0行为变更 FileUriExposedException解决方案 框架
-
eclipse如何修改android工程的包名?
-
解决Android Studio4.1没有Gsonfomat插件,Plugin “GsonFormat” is incompatible的问题
-
android开发如何进行UI布局
-
解决Android Studio4.0:Could not find com.android.tools.build:gradle:5.1.1. Searched in the following