本帖最后由 李印东老师 于 2015-3-27 09:15 编辑
Handler 消息机制(源码分析)
其中有四个关键对象分别是: Message,Handler, MessageQueue, Looper.
创建一个Message消息对象.- Message msg = new Message();
- // 先去消息池中去取, 如果没有再new一个
- Message msg = Message.obtain();
复制代码
创建一个Handler对象, 以下是Handler类的构造函数代码片段:
- public Handler() {
- ...
- // 取得Looper对象
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handlerinside thread that has not called Looper.prepare()");
- }
- // 消息队列
- mQueue = mLooper.mQueue;
- mCallback = null;
- }
复制代码
调用sendMessage方法发送一个消息.
- public final boolean sendMessage(Message msg) {
- // 1. 转调sendMessageDelayed
- return sendMessageDelayed(msg, 0);
- }
- public final boolean sendMessageDelayed(Message msg, long delayMillis) {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- // 2. 转调sendMessageAtTime
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- boolean sent = false;
- MessageQueue queue = mQueue;
- if (queue != null) {
- // 3. 这里把msg的target参数赋值为this(当前的Handler对象)
- msg.target = this;
- // 4. 把消息传递给消息队列MessageQueue.
- sent = queue.enqueueMessage(msg, uptimeMillis);
- } else {
- RuntimeException e = new RuntimeException(
- this + "sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- }
- return sent;
- }
复制代码
MessageQueue类, 通过enqueueMessage方法接收Message消息对象, 并按照先后或者时间顺序排列好.
- final boolean enqueueMessage(Message msg, long when) {
- ...
- final boolean needWake;
- synchronized (this) {
- ...
- msg.when = when;
- //Log.d("MessageQueue", "Enqueing: " + msg);
- Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked; // newhead, might need to wake up
- } else {
- Message prev = null;
- while (p != null &&p.when <= when) {
- prev = p;
- p = p.next;
- }
- msg.next = prev.next;
- prev.next = msg;
- needWake = false; // stillwaiting on head, no need to wake up
- }
- }
- ...
- return true;
- }
复制代码
接下来就是Looper轮循器了, 它的工作就是不停的去MessageQueue队列中取消息. Looper的实例对象是在ActivityThread的main方法中初始化的. ActivityThread的main函数, 代码片段如下:
- public static final void main(String[] args) {
- ...
- // 准备主线程的Looper轮循器, 内部会创建一个Looper对象.
- Looper.prepareMainLooper();
- if (sMainThreadHandler == null) {
- sMainThreadHandler = new Handler();
- }
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- if (false) {
- Looper.myLooper().setMessageLogging(new
- LogPrinter(Log.DEBUG,"ActivityThread"));
- }
- // 开始轮循.
- Looper.loop();
- ...
- }
复制代码
Looper类中的loop方法, 代码片段如下; 注意: 这里loop方法是一个while(true)的死循环, 这就引发一个问题: 会不会阻塞主线程? 答案是: Looper的底层涉及到Linux下的管道(Pipe), 管道可以实现进程间通信, 管道内部实现原理: 是由一个特殊的文件来实现的, 此文件的两端有两个描述符, 一个用于读取, 一个用于写入. 这样的话主线程在等待其他线程写入, 如果其他线程写入后会唤醒主线程, 这样的话主线程开始循环取消息, 如果没有消息了, 主线程又开始进入等待(挂起)状态.
- public static final void loop() {
- // 获得主线程Looper对象
- Looper me = myLooper();
- // 获得消息队列
- MessageQueue queue = me.mQueue;
- while (true) { // 循环的去消息队列MessageQueue中取消息.
- // 注意: 如果消息队列中没有消息, 下面这一步就会使主线程进入挂起状态, 直到被唤醒, 再继续取消息, 分发消息.
- Message msg = queue.next(); // might block
- if (msg != null) {
- if (msg.target == null) {
- // No target is a magicidentifier for the quit message.
- return;
- }
- if (me.mLogging!= null)me.mLogging.println(
- ">>>>> Dispatching to " + msg.target + ""
- + msg.callback +": " + msg.what
- );
- // 调用target的dispatchMessage方法分发消息
- msg.target.dispatchMessage(msg);
- if (me.mLogging!= null)me.mLogging.println(
- "<<<<< Finished to " + msg.target + " "
- + msg.callback);
- msg.recycle();
- }
- }
- }
复制代码
Looper调用了Message中的target的dispatchMessage方法分发消息, 上面Handler发送消息时,msg.target对象其实就是Handler自己.Handler的dispatchMessage方法如下:
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- }else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- // 调用了自己的handleMessage方法.
- handleMessage(msg);
- }
- }
- // 此方法是空实现. 是由我们自己定义的Handler对象中实现的.
- public void handleMessage(Message msg) {
- }
复制代码
至此为止, 发送一个消息最终被Handler的handleMessage方法接收到.
|