关于ANR,说点新鲜的

官方文档中的定义:

What Triggers ANR?
  1. No response to an input event (such as key press or screen touch events) within 5 seconds.
    对一个输入事件没能在5s内做出响应。
  2. A BroadcastReceiver hasn't finished executing within 10 seconds.广播接收器在10s内没能结束执行。
ANRs
  1. While your activity is in the foreground, your app has not responded to an input event or BroadcastReceiver (such as key press or screen touch events) within 5 seconds.当你的Activity处于前台,你的应用没有在5s内对一个输入事件或广播接收器做出响应。
  2. While you do not have an activity in the foreground, your BroadcastReceiver hasn't finished executing within a considerable amount of time.当你没有前台Activity,你的广播接收器在一个较长的时间里没能执行结束。

咦,普遍的说法是什么?

大概是这样的:

  1. 应用5s未响应输入事件
  2. 广播接收器10s未执行完成(即onReceive()方法返回。)
  3. 服务在20s内未执行完成。(其实应该说是onStartCommand()没有返回,因为服务的生命周期在onStartCommand()之后仍处于激活状态,只是我们一般都用线程,即使是不用线程,也将逻辑直接写在onStartCommand()里了。)

问题来了

  1. Activity中执行耗时任务,事件超过5s,会不会ANR?
  2. 广播接收器中到底能执行多久?
  3. Service中能执行多久?
第一个问题,是不是Activity中阻塞5s就会出现ANR?
关于ANR,说点新鲜的_第1张图片
Activity中阻塞60s

在上边的测试中,我不断的增大Activity中阻塞的时间,直到60s时,如果不操作手机,仍然不会弹出ANR。
而如果在阻塞期间,你点击屏幕,就会在几秒中之内,弹出ANR。之所以说几秒而不是5s,因为大部分在6-7s左右,有时会到10s,这个我还要再研究一下。

证明了:是输入事件未得到响应引发的ANR,而不是主线程阻塞引起的(虽然主线程阻塞会导致接下来出现的输入事件得不到响应,进而引发ANR)。

第二个问题,广播接收器中到底能执行多久?

这是在后台执行的情况:

Receiver阻塞30s
Receiver仍然没有ANR

可以看到30s没问题,后续加到60s时也没问题,但到90s时,可以从调试器看到进程死掉。但不会有ANR出现。

那前台呢?
我把发送广播的应用的代码改一下,广播延时5s执行。这时候我会打开接收广播的应用。

Handler().postDelayed(
                        { sendBroadcast(intent) }, 5000)
关于ANR,说点新鲜的_第2张图片
Receiver处于前台

第一个log是我确认延时没问题,第二个log是前台阻塞60s后打印的。嗯,阻塞60s没问题,前台后台都一样。

那Service呢?

我觉得看到这里,你可能觉得,Service也一样,只是阻塞主线程,如果没输入事件就不会导致ANR。

看我这个语气,你就知道事情没那么简单,经过多次测试,Service的onStartCommand()中阻塞20s以上,直接ANR。19s就没有问题,哇,你竟然按套路出牌了!

总结ANR出现的原因

  1. 输入事件没能得到及时的响应。因为广播接收器的onReceive()方法也是执行在主线程中的,所以也会阻塞主线程,导致之后的输入事件得不到响应。注意这个“之后的输入事件”,上边已经多次证明了,仅仅只是阻塞线程不会导致ANR
  2. Service的onStartCommand()方法20s内未返回。

使用的测试机信息:Sony Xperia Z5,Android7.1.1

你可能感兴趣的:(关于ANR,说点新鲜的)