android优化-ANR介绍和追踪

2,170 阅读3分钟

概述

ANR(Application Not Responding): 应用无响应.如果 Android 应用的界面线程处于阻塞状态的时间过长,会触发“应用无响应”(ANR) 错误。如果应用位于前台,系统会向用户显示一个对话框

什么情况下回产生ANR

通常,当应用无法响应用户输入时,系统即会显示 ANR。例如,如果应用在界面线程中屏蔽了某些 I/O 操作(通常是网络访问),导致系统无法处理传入的用户输入事件。或者,应用在界面线程中花费太多时间构建复杂的内存结构或计算游戏的下一个走法。确保高效的计算始终至关重要,但即使最高效的代码仍然需要时间来运行

ANR类型

  • KeyDispatchTimeout:如果按键或屏幕轻触事件或者输入框在5s的时间内没有处理完成。 (这个不一定阻塞主线程之后就会产生ANR,而是在相应事件的超时时才会,比如Activity的onCreate中Sleep(10s),如果此时没有按返回键呀,点击其他的按键呀,其实并不会触发ARN弹窗),不知为什么我在我手机始终无法弄出来这样的ANR
  • BroadcastTimeout:分为前台广播前台10s,后台广播60s。
  • ServiceTimeout:前台服务20s,后台服务200s的时间内没有处理完成。

一般后台 ARN 弹窗默认是不开启的,只有在设备的开发者选项中启用了显示所有 ANR 时,Android 才会针对花费过长时间处理广播消息的应用显示 ANR 对话框。因此,系统并不会始终向用户显示后台 ANR 对话框,但应用仍可能会遇到性能问题。

超时时间是在 ActivityManagerService 和 ActiveServices 定义的

# ActivityManagerService
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;

// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;

# ActiveServices
 // How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;

// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

诊断 ANR 时需要考虑以下几种常见模式

总结一句话,主线程不要做耗时操作,就算没有产生ANR,但是如果要用户几秒之内没反映的话,肯定对用户的体验不好的

  • 应用在主线程上非常缓慢地执行涉及 I/O 的操作。
  • 应用在主线程上进行长时间的计算
  • binder 一般默认的是同步调用,所以会堵塞线程
  • 主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态
  • 主线程处于阻塞状态

使用 StrictMode

使用 StrictMode 有助于您在开发应用时发现主线程上的意外 I/O 操作。您可以在应用级别或 Activity 级别使用 StrictMode

拉取 堆栈信息(需要root)

较低的操作系统版本中,设备上只有一个 /data/anr/traces.txt 文件。在较新的操作系统版本中,有多个 /data/anr/anr_* 文件

使用 ANR-WatchDog

首先,我们调用了ANR-WatchDog的start方法,然后这个线程就会开始工作。 然后,我们通过主线程的Handler post一个消息将主线程的某个值进行一个加值的操作。 post完成之后呢,我们这个线程就sleep一段时间。 在sleep之后呢,它就会来检测我们这个值有没有被修改,如果这个值被修改了,那就说明我们在主线程中执行了这个message,即表明主线程没有发生卡顿,否则,则说明主线程发生了卡顿。 最后,ANR-WatchDog就会判断发生了ANR,抛出一个异常给我们

参考链接

深入探索Android卡顿优化 官网