Handler+Messagequeue+looper

2017-06-04  本文已影响0人  李海洲

本文讨论Android的消息机制,基于Android7.1代码,旨在通过本文对Android的消息机制有一个基础的认识
主要分三部分进行讨论:Handler、Looper、MessageQueue
Part1:Handler部分 【frameworks/base/core/java/android/os/Handler.java】
Handler的sendMessage方法层层跟进最终调用到了sendMessageAtTime方法,如下所示


图片.png 图片.png 图片.png

这里的Queue来自于looper


图片.png

从此处代码可以看出,Handler与Looper,和MessageQueue正是在此处关联起来的


图片.png

Part2:Looper部分【frameworks/base/core/java/android/os/Looper.java】


图片.png

另外,再看下Looper的构造函数

图片.png

MessageQueue包装在了Looper对象中

由此可以看出,通过ThreadLocal使得线程和Looper关联上,因为MessageQueue包装在了Looper对象中,从而消息队列与线程关联上,并且不同的线程就不能访问对方的消息队列。
三者关系图如下

图片.png 图片.png

这里说下TLS即线程局部存储(Thread Local Storage,TLS),通过TLS机制,为每一个使用该全局变量的线程都提供一个变量值的副本,每一个线程均可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。而从全局变量的角度上来看,就好像一个全局变量被克隆成了多份副本,而每一份副本都可以被一个线程独立地改变。
这里的代码就是为每个线程创建一个自己的Looper副本,而不用synchronized同步机制来处理,A线程改变了A的looper副本,不影响B线程的Looper,从而比较高效的实现线程安全。

上面代码可以看出在Looper准备好后,线程会调用Looper.loop(),进入真正的循环机制。loop()函数的代码流程非常简单,只不过是在一个for循环里不停从消息队列中摘取消息,而后调用msg.target.dispatchMessage()对消息进行派发处理而已。
这里的msg.target域比较重要,这个域记录的其实就是当初向消息队列发送消息的那个handler。

Part3:MessageQueue部分【frameworks/base/core/java/android/os/MessageQueue.java】
Handler的sendMessageAtTime()时,最终会调用queue.enqueueMessage()将消息push进消息队列
这里对消息链表里如何插入Message,以及消息队列如何感知消息变化的,这里不多加介绍,牵涉到管道和epoll机制。可以自行阅读MessageQueue.java的enqueueMessage方法追下去

这里顺便说下我们平时定义Handler的较好做法


图片.png

小结:
通过Handler向Looper的消息队列中插入Message,而后再由Looper在消息循环里具体处理。因为消息队列本身不具有链表一变动就能马上感知的功能,所以它需要借助管道和epoll机制来监听变动。当外界向消息队列中打入新消息后,就向管道的“写入端”写入简单数据,于是epoll可以立即感知到管道的变动,从何激发从消息队列中摘取消息的动作。这就是Android消息机制的大体情况。

本文参考文章
https://my.oschina.net/youranhongcha/blog/492591
http://www.jb51.net/article/81932.htm

上一篇下一篇

猜你喜欢

热点阅读