【Android】Android ANR:原理分析及解决办法

本文详细介绍了Android ANR(应用程序无响应)的原理,包括InputDispatching Timeout、BroadcastQueue Timeout和Service Timeout等触发条件。通过Log、traces.txt、Java线程调用分析和DDMS等方法进行ANR分析,并针对不同原因提供了相应的解决办法。同时,文章还深入探讨了Service、BroadcastReceiver和ContentProvider造成的ANR源码分析。
摘要由CSDN通过智能技术生成

在这里插入图片描述

一、ANR说明和原因

1.1 简介

ANR全称:Application Not Responding,也就是应用程序无响应。

1.2 原因

Android系统中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。

以下四个条件都可以造成ANR发生:

InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。
Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕。
ContentProvider Timeout :ContentProvider的publish在10s内没进行完。

1.3 避免

尽量避免在主线程(UI线程)中作耗时操作。

那么耗时操作就放在子线程中。
关于多线程可以参考:Android多线程:理解和简单使用总结

二、ANR分析办法

2.1 ANR重现

这里使用的是号称Google亲儿子的Google Pixel xl(Android 8.0系统)做的测试,生成一个按钮跳转到ANRTestActivity,在后者的onCreate()中主线程休眠20秒:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_anr_test);
    // 这是Android提供线程休眠函数,与Thread.sleep()最大的区别是
    // 该使用该函数不会抛出InterruptedException异常。
    SystemClock.sleep(20 * 1000);
}

在进入ANRTestActivity后黑屏一段时间,大概有七八秒,终于弹出了ANR异常。
在这里插入图片描述

Google Pixel xl ANR.png

2.2 ANR分析办法一:Log

刚才产生ANR后,看下Log:

在这里插入图片描述

ANR Log.png

可以看到logcat清晰地记录了ANR发生的时间,以及线程的tid和一句话概括原因:WaitingInMainSignalCatcherLoop,大概意思为主线程等待异常。
最后一句The application may be doing too much work on its main thread.告知可能在主线程做了太多的工作。

2.3 ANR分析办法二:traces.txt

刚才的log有第二句Wrote stack traces to ‘/data/anr/traces.txt’,说明ANR异常已经输出到traces.txt文件,使用adb命令把这个文件从手机里导出来:

cd到adb.exe所在的目录,也就是Android SDK的platform-tools目录,例如:

cd D:\Android\AndroidSdk\platform-tools

此外,除了Windows的cmd以外,还可以使用AndroidStudio的Terminal来输入adb命令。

到指定目录后执行以下adb命令导出traces.txt文件:

adb pull /data/anr/traces.txt

traces.txt默认会被导出到Android SDK的\platform-tools目录。一般来说traces.txt文件记录的东西会比较多,分析的时候需要有针对性地去找相关记录。

----- pid 23346 at 2017-11-07 11:33:57 -----  ----> 进程id和ANR产生时间
Cmd line: com.sky.myjavatest
Build fingerprint: 'google/marlin/marlin:8.0.0/OPR3.170623.007/4286350:user/release-keys'
ABI: 'arm64'
Build type: optimized
Zygote loaded classes=4681 post zygote classes=106
Intern table: 42675 strong; 137 weak
JNI: CheckJNI is on; globals=526 (plus 22 weak)
Libraries: /system/lib64/libandroid.so /system/lib64/libcompiler_rt.so 
/system/lib64/libjavacrypto.so
/system/lib64/libjnigraphics.so /system/lib64/libmedia_jni.so /system/lib64/libsoundpool.so
/system/lib64/libwebviewchromium_loader.so libjavacore.so libopenjdk.so (9)
Heap: 22% free, 1478KB/1896KB; 21881 objects    ----> 内存使用情况

"main" prio=5 tid=1 Sleeping    ----> 原因为Sleeping
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x733d0670 self=0x74a4abea00
  | sysTid=23346 nice=-10 cgrp=default sched=0/0 handle=0x74a91ab9b0
  | state=S schedstat=( 391462128 82838177 354 ) utm=33 stm=4 core=3 HZ=100
  | stack=0x7fe6fac000-0x7fe6fae000 stackSize=8MB
  | held mutexes=
  at java.lang.Thread.sleep(Native method
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值