ANR是Android中一个独有的概念,它的全称是Application Not Responding(应用程序无响应)。

ANR的直观体验是用户在操作APP的过程中,感觉界面卡顿,比如按下某个按钮,打开某个页面等,当卡顿超过一定时间(一般是5秒)时就会出现ANR对话框,如下图所示:

这时查看Logcat,一般可以发现ANR以及traces.txt等字样。可以发现,出现ANR主要是因为我们在主线程中做了耗时操作。这时你可以选择“等待”按钮,等待应用程序结束主线程耗时操作,或者选择“确定”按钮,结束这个应用程序。

1、ANR产生的原因

只有当应用程序的UI线程响应超时才会引起ANR,超时产生原因一般有两种:

· 当前的事件没有机会得到处理,列如UI线程正在响应另外一个事件,当前事件由于某种原因被阻塞了。

· 当前的事件正在处理,但是由于耗时太长没能及时完成。

根据ANR产生的原因不同,超时时间也不尽相同,从本质上讲,产生ANR的原因有三种,大致可以对应到Android中四大组件中的三个(Activity/View、BroadcastReceiver和Service)。

KeyDispatchTiemout

最常见的一种类型,原因是View的按键事件或者触摸事件在特定的时间(5秒)内无法得到响应。

BroadcastTiemout

原因是BroadcastReceiver的onReceive()函数运行在主线程中,在特定的时间(10秒)内无法完成处理。

ServiceTiemout

比较少出现的一种类型,原因是Service的各个生命周期函数在特定时间(20秒)内无法完成处理。

2、ANR时系统做了什么

1).弹出一个对话框

2).将ANR信息输出到traces.txt文件中

traces.txt文件是一个ANR记录文件,用于开发人员调试,目录位于/data/anr中,无需root权限即可通过pull命令获取,下面的命令可以将traces.txt文件拷贝到当前目录下

adb pull /data/anr

3).将ANR信息输出到Logcat中

3、典型的ANR问题场景

· 应用程序UI线程存在耗时操作,例如在UI线程中进行网络请求、数据库操作或者文件操作,可能会导致UI线程无法及时处理用户输入等。当然在Android4.0之后,如果在UI线程中进行网络操作,将会抛出NetworkOnMainThreadException异常。

· 应用程序的UI线程等待子线程释放某个锁,从而无法处理用户的输入。

· 耗时的动画需要大量的计算工作,可能导致CPU负载过量。

· 其它线程终止或崩溃导致主线程一直等待。

· service忙导致超时无响应。

· system server中发生WatchDog ANR。

· service binder的数量达到上限。

· 硬件操作(比如camera)。

4、ANR的定位和分析

当发生ANR时,开发者可以通过结合Logcat日志和生成的位于手机内部存储的/data/anr/traces.txt文件进行定位和分析。

5、ANR的避免和检测

1).避免在主线程执行耗时操作,所有耗时操作应新开一个子线程完成,然后再在主线程更新UI。

2).BroadcastReceiver要执行耗时操作时应启动一个service,将耗时操作交给service来完成。

3).避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广 播时需要向用户展示什么,你应该使用Notification Manager来实现。

UI线程尽量只做跟UI相关的工作

耗时的工作(比如数据库操作,I/O,网络操作),采用单独的工作线程处理

用Handler来处理UIthread和工作thread的交互

UI线程,例如:

Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc

AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc

Mainthread handler: handleMessage(), post*(runnable r), etc

ANR分析:需要关注CPU/IO,trace死锁等数据。

为了避免在开发中引入可能导致应用发生ANR的问题,除了切记不要在主线程中作耗时操作。

6、我们也可以借助于一些工具来进行检测,从而更有效的避免ANR的引入。

6.1StrictMode

严格模式StrictMode是Android SDK提供的一个用来检测代码中是否存在违规操作的工具类,StrictMode主要检测两大类问题:

下面是启用StrictMode的实例,可以在Application的OnCreate中添加,这样就能在程序启动的最初一刻进行监控了。

private void setStrictMode() {

if (Integer.valueOf(Build.VERSION.SDK) > 3) {

Log.d(LOG_TAG, "Enabling StrictMode policy over Sample application");

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()

.detectAll() // 这里可以替换为.detectDiskReads().detectDiskWrites().detectNetwork()。

// detectAll() 包括了磁盘读写和网络I/O

.penaltyLog() //打印logcat,当然也可以定位到dropbox,通过文件保存相应的log

.penaltyDeath()

.build());

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

.detectAll()

.penaltyLog()

.build());

}

}

· 线程策略ThreadPolicy

- detectCustomSlowCalls: 检测自定义耗时操作。

- detectDiskReads: 检测是否存在磁盘读取操作。

- detectDiskWrites: 检测是否存在磁盘写入操作。

- detectNetwork: 检测是否存在网络操作。

线程相关策略,包括主线程访问网络、磁盘(现在手机中使用闪存)读写、慢代码的检测。我们能够分别检测(detect) 这些操作或允许(permit)这些操作。一旦出现了违规(violation),就会有相应的提示(比如 Log 显示)。我们可以使用 detectNetwork() 检测主线程网络访问,detectDiskReads() 和 detectDiskWrites() 检测主线程磁盘读写,detectCustomSlowCalls() 检测主线程自定义的慢代码。当然也可以使用 permitXXX() 允许这些操作。

自定义慢代码分析,是仅当访问调用类的时后才触发的,可以通过这种方法去监视运行缓慢的代码。当在主线程中调用时, 这些验证规则就会起作用去检查你的代码。比如,当你的应用在下载或者解析大量的数据时,你可以触发自定义运行速度慢代码的查询分析, 作用很大。StrictMode可以用于捕捉发生在应用程序主线程中耗时的磁盘、网络访问或函数调用,可以帮助开发者使其改进程序, 使主线程处理UI和动画在磁盘读写和网络操作时变得更平滑,避免主线程被阻塞的发生。

· 虚拟机策略VmPolicy

- detectActivityLeaks: 检测是否存在Activity泄漏。

- detectLeakedClosableObjects: 检测是否存在未关闭的Closeable对象泄漏。

- detectLeakedSqlLiteObjects: 检测是否存在Sqlite对象泄漏。

- setClassInstanceLimit: 检测类实例个数是否超过限制。

虚拟机相关的策略,包括 SQLite 或 SQLiteCursor 没关闭、实现 Closable 接口的类使用后没关闭 等。 我们可以使用detectLeakedSqliteObjects() 检测 SQLite 和 SQLiteCursor 内存泄漏(没关闭),detectLeakedClosableObjects() 检测实现 Closable 接口的对象内存泄漏。

我们能通过 StrictMode.getThreadPolicy() 和 StrictMode.getVMPolicy() 获得当前采取的 ThreadPolicy 和 VMPolicy。

你可以决定当一个异常发生时该发生什么样的事情,比如,使用StrictMode的penaltyLog()方法你可以在应用发生异常时查看adb logcat的输出。 penaltyLog()表示将警告输出到LogCat,你也可以使用其他或增加新的惩罚(penalty)函数,例如使用penaltyDeath()的话,一旦StrictMode消息被写到LogCat后应用就会崩溃。和ThreadPolicy不同的是,VmPolicy不能通过一个对话框提供警告。

因为设置发生在线程中,严苛模式(StrictMode)甚至能在从一个对象到另一个对象的控制流中找到违例事件。当违例发生, 你会惊奇地注意到代码正运行于主线程,而栈trace将帮助你发现它如何发生。于是你能单步调试解决问题,或是将代码移到它自己的后台线程, 或是就保持原来的处理方式。这都取决与你。当然,你可能希望适时关闭严苛模式(StrictMode),当你的程序作为产品发布时, 你可不希望它仅为了一个警告在你的用户手里崩溃。有两个方法可以关闭严苛模式(StrictMode),最直接的就是移除相应代码, 但这样做不利于持续开发的产品。你通常可以定义一个应用级别布尔变量来测试是否需要调用严苛模式(StrictMode)代码。 在发布产品前将这个值定义为FALSE。更优雅的方式是利用调试模式(debug mode)的特点,在AndroidManifest.xml中定义这个布尔变量。

字段的属性之一是android:debuggable,其义自明。 某些时候你不希望报告所有违例。那在主线程之外的其他线程中设置严苛模式(StrictMode)很不错。譬如,你需要在正在监视的线程中进行磁盘读取。 此时,你要么不去调用detectDiskReads(),要么在调用detectAll()之后跟一个permitDiskReads()。类似允许函数也适用于其他操作。 当你发现一个比较严重的异常时,Android提供了一系列的工具来解决它:线程、Handler、AsyncTask、IntentService等等。但并不是StrictMode 报的所有问题都需要修复,特别是很多必须要在窗口生命周期回调中访问磁盘的时候。使用严苛模式可以帮你解决很多问题,比如在UI线程中访问网络始终 是一个问题。 当应用启用了strictmode模式时,其实跟普通的应用没什么两样,在测试和运行时,跟平时运行普通应用程序一样就可以了。 当启用了Strictmode模式时,会监视所有的程序运行情况,当发现出现重大问题或违背策略规则时,会提示用户。 下面是当运行启用了strictmode模式的应用时,当发现违背规则时,显示给用户的信息。

6.2 BlockCanary

BlockCanary是一个非侵入式的性能监控函数库,它的用法和LeakCanary类似,只不过LeakCanary监控应用的内存泄漏,而BlockCanary主要用来监控应用主线程的卡顿。它的基本原理是利用主线程的消息队列处理机制,通过对比消息分发开始和结束的时间点来判断是否超过设定的时间,如果是,即判断为主线程卡顿。它的集成很简单,首先在build.gradle中添加在线依赖,如下:

dependencies {

compile 'com.github.moduth:blockcanary-android:1.2.1'

// 仅在debug包中启用BlockCanary进行卡顿监控和提示的话,可以这么用

debugCompile 'comgithub.moduth:blockcanary-android:1.2.1'

releaseCompile 'comgithub.moduth:blockcanary-no-op:1.2.1'

}

然后在Application类中进行配置和初始化即可,

public class DemoApplication extends Application {

@Override

public void onCreate() {

// 在主进程初始化调用

BlockCanary.install(this, new AppBlockCanaryContext()).start());

}

}

android模拟anr,Android ANR相关推荐

  1. android模拟摄像头,android模拟器如何连接摄像头

    Android模拟器默认的地址是10.0.2.3,默认的DNS也是10.0.2.3,对于在家里上网学习Android的人来讲,一般电脑的IP都是192.168.1.100之类的,不在同一个网段.所以就 ...

  2. android模拟登陆,Android模拟登录V2EX

    最近在撸一个V2EX的客户端,官方API缺少一些功能如登录,发帖等,撸完官方API总觉得少了什么,本篇文章主要通过模拟登录实现一些官方没提供API的功能 观察登录传输的数据 在网页上登录帐号,通过ch ...

  3. Android进阶知识:ANR的定位与解决

    1.前言 ANR对于Android开发者来说一定不会陌生,从刚开始学习Android时的一不注意就ANR,到后来知道主线程不能进行耗时操作注意到这点后,程序出现ANR的情况就大大减少了,甚至于消失了. ...

  4. android webview framework,android – Webview导致ANR

    我编写了一个应用程序,它在Webview中显示html页面,这些页面在ViewPager中管理.一切正常,但是从一页翻到另一页时我有几个ANR. ANR数据转储显示主线程已通过ThreadedRend ...

  5. android dropbox anr分析,Android如何分析排查ANR

    释放双眼,带上耳机,听听看~! 在Android开发中,当程序发生异常时会抛出异常信息,先说下三种常见类型: 列表内容KeyDispatchTimeout(谷歌default 5s,MTK平台上是8s ...

  6. Android App优化之ANR详解

    引言 背景:Android App优化, 要怎么做? Android App优化之性能分析工具 Android App优化之提升你的App启动速度之理论基础 Android App优化之提升你的App ...

  7. Android 系统(55)---Android App开发之ANR异常的原因分析及处理总结

    Android App开发之ANR异常的原因分析及处理总结 Android App开发之ANR异常的原因分析及处理总结 ANR的全称是application not responding,根据它的意思 ...

  8. android开发中的ANR异常

    android开发中的ANR异常 参考文章: (1)android开发中的ANR异常 (2)https://www.cnblogs.com/yejiurui/archive/2012/11/08/27 ...

  9. (六十五)Android O StartService的 anr timeout 流程分析

    前言:之前在(六十四)Android O Service启动流程梳理--startService 梳理了startService的一般流程,anr的没有涉及,本篇就以anr的为关注点梳理下流程. 参考 ...

  10. Android如何分析排查ANR

    在Android开发中,当程序发生异常时会抛出异常信息,先说下三种常见类型: 列表内容KeyDispatchTimeout(谷歌default 5s,MTK平台上是8s) –主要类型 按键或触摸事件在 ...

最新文章

  1. Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch
  2. jquery调取java接口_jQuery方式实现ajax接口调用
  3. 自动化电子测试软件,自主开发的MIL测试自动化测试工具
  4. 前端学习(2561):页面更新
  5. 使用telephonymanager真机调试 闪退_watchOS 上的一次 SKView 内存泄露调试
  6. 软考网络工程师学习笔记6-无线通信网
  7. SaltStack 部署案例 02
  8. java乱码解决方法
  9. 移动端触屏滑动touches使用
  10. mysql管理数据 并上传至云端_西部数码网站管理助手创建、导入恢复、导出备份mysql数据库...
  11. 算法导论9:栈的链表实现 2016.1.9
  12. Java 将Word转为OFD
  13. 大M单纯形算法的MATLAB实现
  14. 时间类计算:双代号网络图、单代号网络图、时标网络图
  15. 二值化网络(BNN)如何训练?这篇ICML 2021论文给你答案
  16. JDK-8274609 JEP 421: Deprecate Finalization for Removal
  17. mybatis使用注解的时候,找不到映射:Type interface com.dao.UserDao is not known to the MapperRegistry.
  18. chrome浏览器去除蓝色边框和黄色背景色
  19. 提前还清房贷的感觉真好
  20. Unity3D教程:如何利用Shader实现钻石渲染效果

热门文章

  1. 通过top查看程序cpu使用率为什么会超过100%
  2. 分享一个网页截图html代码
  3. 如何让Bing快速收录你的网站?
  4. 让你两分钟明白什么是ERP
  5. Linux命令详解之 cp
  6. Random类:用来产生随机数字
  7. mysql 删除临时表的语句_MySQL如何创建和删除临时表_MySQL
  8. win7 批处理文件默认以管理员身份运行及清除IE缓存脚本
  9. 学习python量化分析
  10. 猫游记页游mysql_5款曾经极其火爆的页游,最后一款90后没听过80后才玩过