概述
关于Android消息的处理机制,网上有太多的资料,之前也看过一些,但老实讲印象都不太深刻,尤其对这种理论性特别强的知识点,更是看得多也忘得多。今天我尝试按自己理解的方式来表述一下Android消息的处理机制,当然之前也是有查阅过很多资料的,话不多说,如下:
- Handle:
关于消息传递,通常我们接触最多应该就是Handle了,因为我们总是会在后台获取到消息后通过Handle来通知主线程(UI线程)来更新控件,最简单明了的一句代码就是handler.sendMessage(message),就能让主线程知道接下来我要干什么了。所以我们可以简单的把Handle当作两个线程之间通信的使者,因为使者通常会携带者信息(message)。 - Message:
Message很容易理解,就是我们需要传递的消息。 - Looper:
大家有没有想过主线程跟其他线程的区别,为什么主线程可以作为主线程呢(问的有点玄乎)。首先主线程一定是线程,这个毋庸置疑,当我们点击进入应用的时候,至少会有3个线程,2个Binder线程和一个主线程。我们知道线程也有生命周期的,通常执行完代码,线程就会终止,既然终止了,那我们的应用还怎么跑下去呢,所以我们需要在主线程加入死循环,让程序一直在运作,而Looper就起到了重要作用。主线程不停的循环来等待发来的消息(例如更新UI,Activity的启动等等),消息一进来,主线程就会做出相应的处理,这就是Looper的作用。所以主线程是个无限循环的线程,不断的循环遍历发送给它的消息,做出相应的处理。那么多条消息在主线程中是如何运作的呢?当没有消息的时候,主线程就会进入休眠状态,释放cpu的资源。再看MessageQueue。 - MessageQueue:
看到Queue就知道是队列,当主线程收到消息的时候,会把处在休眠状态中的主线程唤醒,消息存在于MessageQueue中的。一个线程不能同时处理多个消息,所以MessageQueue可以把这些消息以列表的形式一个个拿出来交给主线程做处理。
这里结合源码再分析一下。
源码分析
以前学习Java的时候我们知道程序的入口就是main()方法,那么在Android中,那Java程序入口在哪里呢?且看ActivityThread.class
Looper.class:
我们可以看到在prepareMainLooper() 创建了一个 Looper 对象,并放入ThreadLocal
问题研究
主线程中的Looper.loop()一直无限循环为什么不会造成ANR?结合上面的分析能回答出来吗? - 在looper启动后,主线程上执行的任何代码都是被looper从消息队列里取出来执行的。也就是说主线程之后都是通过其他线程给它发消息来实现执行其他操作的。生命周期的回调也是如此的,系统服务ActivityManagerService通过Binder发送IPC调用给APP进程,App进程接到到调用后,通过App进程的Binder线程给主线程的消息队列插入一条消息来实现的。也就是说假如出现ANR的情况,那是因为当主线程给其他线程发消息后,其他线程未能及时处理执行,才导致的ANR。