Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2019-03-19:ANR 出现的场景以及解决方案?

Moosphan opened this issue · comments

2019-03-19:ANR 出现的场景以及解决方案?
commented

Android系统中,AMS和WMS会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。
例如键盘输入事件和触摸事件超过五秒就会GG
前台广播10秒没有完成 后台60秒吧
服务前台20秒 后台200秒
解决笼统一下尽量使用子线程,避免死锁的出现,使用子线程来处理耗时操作或阻塞任务。
还有就是服务内容提供者吧尽量不要执行太长时间的任务。

在Android中,应用的响应性被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视。当用户触发了输入事件(如键盘输入,点击按钮等),如果应用5秒内没有响应用户的输入事件,那么,Android会认为该应用无响应,便弹出ANR对话框。而弹出ANR异常,也主要是为了提升用户体验。

解决方案是对于耗时的操作,比如访问网络、访问数据库等操作,需要开辟子线程,在子线程处理耗时的操作,主线程主要实现UI的操作

我遇到过一个实际的场景, ContentResover 拿数据的时候是串行的, 看一下 binder 相关的东西, 论证一下;
在UI线程直接用解析者拿数据, 就有可能造成 ANR;

我觉得主要是Android中View不是线程安全的,为了保证线程安全和性能就弄了一个单线程的模型,即UI线程,来做绘制的一些操作。所有的UI线程的绘制必须在16ms内完成(保证60帧运行),所以Android里面会存在ANR的提示来保证这个原则。

我觉得主要是Android中View不是线程安全的,为了保证线程安全和性能就弄了一个单线程的模型,即UI线程,来做绘制的一些操作。所有的UI线程的绘制必须在16ms内完成(保证60帧运行),所以Android里面会存在ANR的提示来保证这个原则。

你前面说的是对的,不过跟Anr无关。ANR本质是个检测工具,用来提示用户和开发者App主线程中某个操作耗时太久并长时间未返回,这是android官方对App主线程性能的限制。

在主线程进行耗时操作,导致用户的操作没得到及时的响应 就会报出 Application Not Response 的问题 即ANR 。
这种情况往往涉及到四大组件,四大组件都是运行在主线程上的。各个组件的耗时时长不同。大概是在activity是五秒 ,广播是十秒 ,service是20秒 无响应 就会报错。
解决方法 即不要在主线程做耗时操作咯,异步处理耗时操作。

出现的原因:ui线程响应超时,出现超时的原因可能是ui线程发生阻塞不能及时处理当前事件,超过5s。
在BroadcastReceiver执行了耗时操作,超过10s没处理完成。

场景
1、触摸无响应5s
2、BroadCastReciver 前台处理超过10s 后台超过60s
3、Server 前台处理超过20s 后台超过200s

ANR出现的类型有两种
1、主线程耗时导致
2、CPU、内存、IO 占用过高资源耗尽(其他进程也可以导致)

如何避免
1、不要在主线程中做耗时的操作
2、避免CPU占用过高,简化方法,减少执行时间
3、避免内存占用过高,防止内存泄漏

推荐看下官方 ANR 文档:
https://developer.android.com/topic/performance/vitals/anr?hl=zh-cn

ANR 出现的场景

  1. 应用在主线程上非常缓慢地执行涉及 I/O 的操作。
  2. 应用在主线程上进行长时间的计算。
  3. 主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。
  4. 主线程处于阻塞状态,为发生在另一个线程上的长操作等待同步的块。
  5. 主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。
  6. 执行速度缓慢的广播接收器。

解决方式:

首先,通过各种方式定位问题

  • 使用 StrictMode 有助于开发应用时发现主线程上的意外 I/O 操作
  • 启用后台 ANR 对话框,只有在设备的开发者选项中启用了显示所有 ANR 时,Android 才会针对花费过长时间处理广播消息的应用显示 ANR 对话框
  • 使用 TraceView 在查看用例时获取正在运行的应用的跟踪信息,并找出主线程繁忙的位置
  • 通过 ANR 日志定位问题

解决问题

  1. 将执行速度缓慢的代码放到子线程处理, 比如耗时的计算
  2. 主线程上耗时的 I/O 放到子线程处理
  3. 查看对主线程所需资源持有的锁,将持有锁的时间降到最少,或者评估应用是否需要持有锁。如果使用锁来确定何时根据工作线程的处理情况来更新界面,请使用 onProgressUpdate() 和 onPostExecute() 之类的机制在工作线程和主线程之间进行通信。
  4. 对于 BroadcastReceiver 的 onReceive() 方法执行长时间运行的操作导致的 ANR, 可以将长时间运行的操作移至 IntentService。

在UI线程执行耗时的操作会导致ANR
Activity 5秒 广播10秒 服务20秒
内存 CPU 占用多过也会导致ANR
解决方法
耗时操作不要在UI线程中执行
避免过多的占用内存 防止内存泄漏

  • Service Timeout:比如前台服务在20s内未执行完成,后台服务Timeout时间是前台服务的10倍,200s;
  • BroadcastQueue Timeout:比如前台广播在10s内未执行完成,后台60s;
  • ContentProvider Timeout:内容提供者,在publish过超时10s;
  • InputDispatching Timeout: 输入事件分发超时5s,包括按键和触摸事件。