您的位置:首页 > 移动开发 > Android开发

Android ANR 原因分析与检测

2017-09-27 00:02 99 查看

Android ANR 原因分析与检测

ANR,即应用程序不响应(Application Not Responding)。在主线程中进行某些耗时操作,超过一定时间,系统就会弹出ANR对话框。此时可以选择等待,让程序跑完,也可以选择关闭应用程序。

一、 ANR 原因分析

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

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

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

本质上,产生ANR的原因有三种:KeyDispatchTimeout、BroadcastTimeout、ServiceTimeout

1.1 KeyDispatchTimeout

View的按键事件或者触摸事件这特定事件(5秒)内无法得到响应

1.2 BroadcastTimeout

BroadcastReceiver 的 onReceive()方法在特定时间(10秒)内无法完成处理(onReceive是运行在主线程的)

1.3 ServiceTimeout

Service 的各个生命周期函数在特定时间(20秒)内无法完成处理

二、ANR 避免

一个原则:主线程尽量只做UI相关的事,耗时操作(如文件读取,数据库读写等),计算量大的任务,在线程中执行,完成之后通过Handler来更新UI。

2.1 主线程

运行在主线程的有:

1. Activity的各个生命周期 onCreate(),onResume(),onDestory,点击/触摸事件等

2. Service的各个生命周期

3. BroadcastReceiver的onReceive()方法。

4. AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel

5. Mainthread handler: handleMessage(), post*(runnable r)

6. View的post()方法

在以上的这些方法内,尽量不要执行耗时的操作,如读写数据库,文件等。可以放在线程中运行,完成后再通知更新主线程。

2.2 异步处理技术

Android SDK提供了很多异步处理技术

1. Thread + Handler

2. HandlerThread

3. AsyncTask

4. IntentService

5. AsyncQueryHandler(用于ContentProvider上执行异步的CRUD)

6. Loader(Android 3.0引入的一个异步数据加载框架)

除了Android SDK提供的异步技术外,比较火的RxAnroid使用起来更加方便简洁,流程更加清晰,代码更加易于理解,功能更加强大(反正说是牛逼轰轰,确实也是很好用)。

三、ANR 定位分析

发生ANR后,可以结合Logcat日志和位于收集内部存储的/data/anr/trace.txt文件进行分析和定位。Cash和ANR的异常信息统计,一般可以接入第三的统计SDK,如友盟或者Bugly,不需要自己实现后台,便可以实时获得APP的异常统计信息,可以专注于问题的分析和定位。但是,为了更好地理解解决的思路,还是有必要了解信息是的来源和如何收集。

3.1 Logcat 日志信息

发生ANR后,可以查看Logcat日志,日志中有ANR的类型,时间等信息,参考浅谈ANR及log分析ANR

3.2 traces.txt 日志信息

有时候根据Logcat日志无法定位到问题的具体位置,这时候就需要traces.txt中的日志信息。

traces.txt位于设备的 /data/anr/traces.txt文件中(因为权限限制,在应用中无法读取,如果可以读取就可以上报给后台,实现自己的ANR日志收集SDK),链接上PC后可以通过adb命令导出:

adb pull /data/anr/traces.txt C:\Users\YourName\Desktop\traces.txt


如何分析traces.txt日志?参考:

Android App优化之ANR详解

android anr traces日志分析方法

3.3 第三方统计SDK

Logcat 日志和trace.txt日志都需要有设备才能获取到,而实际中几乎不可能拿到用户的设备来查看日志,所以,有必要有一个后台来收集错误信息。第一种方法是自己实现Crash和ANR信息收集;第二种方法是利用现有的第三方平台,如Bugly友盟。使用第三方平台的好处是节约成本,专注于ANR的定位和问题的解决即可。

四、ANR 检测

可以借助一些工具,在调试阶段进行违规代码的检测

4.1 StrictMode

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

线程策略ThreadPolicy

detectCustomSlowCalls 检测自定义耗时操作

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

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

detectNetwork 检测是否存在网络操作

虚拟机策略VmPolicy

detectActivityLeaks 检测是否存在Activity泄漏

detectLeakedClosableObjects 检测是否存在未关闭的Closable对象泄漏

detectLeakedSqlLiteObject 检测是否存在Sqlite对象泄漏

setClassInstanceLimit 检测类实例个数是否超出限制

严格模式的使用并不复杂,在自定义的Application类或者MainActivity的onCreate()方法中加入以下代码即可:

@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {      // 只在debug使用,release不使用严格模式
StrictMode.enableDefaults();
}
}


enableDefaults()的实现如下:

/**
* Enable the recommended StrictMode defaults, with violations just being logged.
*
* <p>This catches disk and network access on the main thread, as
* well as leaked SQLite cursors and unclosed resources.  This is
* simply a wrapper around {@link #setVmPolicy} and {@link
* #setThreadPolicy}.
*/
public static void enableDefaults() {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}


启用了严格模式,在Logcat中过滤:tag = StrictMode即可看到输出的日志信息。然后根据输出的日志信息,检测是否存在问题,然后及时改正。

4.2 BlockCanary

BlockCanary 是一个非侵入式的性能监控函数库,它的用法和LeakCanary类似,只不过后者监控应用的内存泄漏,而BlockCanary主要用来监控应用的主线程卡顿,它的基本原理是利用主线程的消息队列处理机制,通过对比消息分发开始和结束的时间点来判断是否超过设定的时间,如果是则判断线程卡顿,它的集成很简单,在build.gradle中添加依赖: compile ‘com.github.moduth:blockcanary-android:1.2.1’,然后在Application中进行配置和初始化即可。

@Override
public void onCreate() {
super.onCreate();
BlockCanary.install(this, new AppBlockCanaryContext()).start();
}


更多参考:blockcanaryBlockCanary解析

五、扩展

一、实现ANR信息收集SDK

前面介绍中的 Logcat 日志和 traces.txt 文件日志可以作为分析ANR的主要信息,而Logcat日志需要连接到PC利用IDE来查看,traces.txt文件/data/anr/traces.txt是没有读取权限的。所以,如何收集这些信息,上报到后台?(PS: bugly等第三方平台是如何实现的呢?)

六、参考

Android App优化之ANR详解

Android高级进阶

浅谈ANR及log分析ANR

blockcanary

BlockCanary解析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: