前言

本文对Android中常发生的ANR现象的成因原理及主要发生场景进行了详细介绍,举例了几种典型的ANR场景实例。总结提供了优化改善的若干解决思路。
值得Android开发人员收藏

简介

ANR全称:Application Not Responding,也就是应用程序无响应
针对Android中常发生的ANR现象,要解决此问题,当真要从其原理开始分析,如下图所示

原因

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

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

ANR分析办法

ANR重现

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

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

在进入ANRTestActivity后黑屏一段时间,大概有七八秒,终于弹出了ANR异常

ANR分析办法一:Log

刚才产生ANR后,看下Log:

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

ANR分析办法二:traces.txt

刚才的log有第二句Wrote stack traces to '/data/anr/traces.txt',说明ANR异常已经输出到traces.txt文件,使用adb命令把这个文件从手机里导出来:
1、cd到adb.exe所在的目录,也就是Android SDKplatform-tools目录,例如:

cd D:\Android\AndroidSdk\platform-tools

此外,除了Windows的cmd以外,还可以使用AndroidStudioTerminal来输入adb命令。
2、到指定目录后执行以下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.myjavatestBuild fingerprint: 'google/marlin/marlin:8.0.0/OPR3.170623.007/4286350:user/release-keys'ABI: 'arm64'Build type: optimizedZygote loaded classes=4681 post zygote classes=106Intern table: 42675 strong; 137 weakJNI: 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)  - sleeping on <0x053fd2c2> (a java.lang.Object)  at java.lang.Thread.sleep(Thread.java:373)  - locked <0x053fd2c2> (a java.lang.Object)  at java.lang.Thread.sleep(Thread.java:314)  at android.os.SystemClock.sleep(SystemClock.java:122)  at com.sky.myjavatest.ANRTestActivity.onCreate(ANRTestActivity.java:20) ----> 产生ANR的包名以及具体行数  at android.app.Activity.performCreate(Activity.java:6975)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)  at android.app.ActivityThread.-wrap11(ActivityThread.java:-1)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6541)  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:767)

在文件中使用 ctrl + F 查找包名可以快速定位相关代码。
通过上方log可以看出相关问题:

  • 进程id和包名:pid 23346 com.sky.myjavatest
  • 造成ANR的原因:Sleeping
  • 造成ANR的具体行数:ANRTestActivity.java:20类的第20行

特别注意:产生新的ANR,原来的 traces.txt 文件会被覆盖。

ANR分析办法三:Java线程调用分析

通过JDK提供的命令可以帮助分析和调试Java应用,命令为:

jstack {pid}

其中pid可以通过jps命令获得,jps命令会列出当前系统中运行的所有Java虚拟机进程,比如

7266 Test7267 Jps

ANR分析办法四:DDMS分析ANR问题

  • 使用DDMS——Update Threads工具
  • 阅读Update Threads的输出

造成ANR的原因及解决办法

上面例子只是由于简单的主线程耗时操作造成的ANR,造成ANR的原因还有很多:

  • 主线程阻塞或主线程数据读取

解决办法:避免死锁的出现,使用子线程来处理耗时操作或阻塞任务。尽量避免在主线程query provider、不要滥用SharePreferenceS

  • CPU满负荷,I/O阻塞

解决办法:文件读写或数据库操作放在子线程异步操作。

  • 内存不足

解决办法:AndroidManifest.xml文件中可以设置 android:largeHeap="true",以此增大App使用内存。不过不建议使用此法,从根本上防止内存泄漏,优化内存使用才是正道。

  • 各大组件ANR

各大组件生命周期中也应避免耗时操作,注意BroadcastReciever的onRecieve()、后台Service和ContentProvider也不要执行太长时间的任务

本章节暂且结束,后续预告请往下看,如有需要后续文章资料,文末有领取方式

ANR源码分析

crash监控方案

线程监控 - 死锁、存活周期与 CPU 占用率

启动速度与执行效率优化项目实战

Android卡顿检测及优化

  • 卡顿
  • 帧率
  • 卡顿原因
  • 卡顿检测
    使用dumpsys gfxinfo
    使用systrace
    使用BlockCanary

内存优化

  • Android内存优化工具
    top
    dumpsys meminfo
    Memory Profiler
    Leak Canary
    MAT
    内存问题高效分析方法
  • Android内存泄漏分析及检测工具LeakCanary简介
  • 安卓内存优化

「上图展示的只是一部分」
由于文章篇幅有限,后续还有耗电优化、网络传输与数据存储优化、apk大小优化、实战项目等知识要点
有需要的可在我的QQ技术交流群里可以自助拿走,如果在学习或工作中遇到了问题,群里会有一些大神帮忙解答,有时你闷头想一天,不如别人的三言两语就醍醐灌顶,群793544421
加入圈子,免费领取

更多相关文章

  1. 在android 中使用og4j
  2. (转)分析android与java的关系
  3. 每日一道Android(安卓)面试题,面试途中不败题
  4. Android使用XML全攻略(2)
  5. Android中的资源分析
  6. 使用android快速开发框架afinal 开发android应用程序
  7. Android(安卓)页面惯性回弹效果,Nested接口接口简单实现。
  8. 想抢先体验Android操作系统的魅力吗?那就使用Android(安卓)LiveCD
  9. Android使用libjpeg实现图片压缩

随机推荐

  1. Android之SurfaceView学习一
  2. 状态栏通知Notification用法
  3. 仿Iphone右划关闭Activity
  4. Android如何选择targetSDKVersion
  5. android 使用libmad 生成MP3左右声道的PC
  6. Android Sina Oauth use sina sdk and si
  7. Android MediaPlayer 播放音频文件
  8. 我的Android进阶之旅------>Android 设置
  9. android studio 使用专用的sdk和virtual
  10. listView显示多种布局 android