安卓面试Android开发面试

主线程Looper.loop()进入无限循环,为什么不会造成AN

2017-12-21  本文已影响206人  大虾啊啊啊

我们都知道,在主线程创建之后,Looper.loop()会进入无限的循环状态,当没有消息的时候,线程会进入阻塞状态、那为什么不会造成ANR呢?

对于这个问题,首先我们来理解一下什么原因会造成ANR。

1.当前事件没有得到机会处理(有可能是因为主线程正常处理其他的事件,而不能及时处理当前的事件)。

2.当前事件正在处理了,但是没有及时处理完成。

我们知道了造成了ANR原因之后,再来分析一下Looper.loop()会使线程阻塞,为什么又不会造成ANR呢?我们先看下ActivityThread的源码。ActivityThread是主线程的入口类。找到入口main()方法。

我们看到关键的5221行和5223行

5221行,我们看到loop()方法

loop方法121行,会使程序进入到了死循环的状态。当如果没有消息的时候,直接retrurn掉。然后回到main方法的5223行,报了一个异常 thrownewRuntimeException("Main thread loop unexpectedly exited");接着整个主线程就会退出了。所以就是说,在主线程中当loop()方法没有轮询到消息的时候。主线程就直接退出了。所以在这里我们知道了Looper.loop()消息循环的必要性,一旦退出消息循环,那么你的应用也就退出了。

因为Android应用是由事件驱动的。looper.loop()不断的轮询接收事件,handler不断的处理事件。每一个点击触摸事件,或者Activity的生命周期的创建,都是运行在looper.loop()控制之下,简单的来说就是,这些都是属于一个事件消息,然后由looper.loop()轮询到,接着做相应的操作。也就是说,这些这些事件都在looper.loop()循环内执行的。这些事件消息的处理,可能会卡顿,造成了looper.loop()循环的阻塞,而不是looper.loop()阻塞了这些事件。

我们来看下handlerMessage的部分源码

我们看到,Activity的每个生命周期都是由消息驱动的。接收不同的消息,进行不同的生命周期方法,举个例子:假如现在轮询到了onResume这个消息,这个时候, Activity应该执行onResume方法。假如这个时候我们在onResume方法里面执行耗时操作。同时又进行点击事件,那么点击事件就不会得到及时的处理。这样的话,就会造成卡顿,然后ANR了。

小结:Looper.loop()当没有轮询到事件的时候,整个应用程序就退出了,而我们的消息事件都是在Looper.loop()循环内,如果循环内没有得到及时的处理事件,就会造成了ANR.

啰嗦一下:我们可以这样理解,Anroid应用程序的运行,就像车子在行走一样,如果轮子不转了,那么车子也停了,也就是说应用程序也就退出了。当车子一下子遇到很多个石头可能会开的比较慢,甚至卡死了。也就类似于当事件没有得到处理,那么就会造成ANR,卡死。

上一篇下一篇

猜你喜欢

热点阅读