Android Handler消息机制(3)Looper、Message和MessageQueue

197 阅读2分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

Handler机制原理

1.Looper

loop()

 public static void loop() {
     //...
     //返回sThreadLocal存储的Looper实例
     final Looper me = myLooper();
     //拿到该looper实例中的消息队列
     final MessageQueue queue = me.mQueue;
     //...
     for (;;) {
         //取出一条消息,如果没有消息则阻塞等待
         Message msg = queue.next(); 
         if (msg == null) return;
         try {
             //Msg的target其实就是handler对象
             msg.target.dispatchMessage(msg);   
         } 
         //释放资源
         msg.recycleUnchecked();
     }
 }

上述是loop的源码,此处省略部分代码。

loop()方法,不断从MessageQueue中取消息,无则阻塞,等待消息。有则交给消息的target属性(handler对象)的dispatchMessage方法去处理。

上面介绍了 msg.target其实就是Messager所属的Handler。

后面会具体介绍Handler并对此进行说明。

2.Message

Message 是线程通信中传递的消息,使用what进行消息的区分,使用 arg1、arg2、obj、data 进行数据的传递,参数 target它决定了 Message 所关联的 Handler。上面也提到了这一点,后续会进行分析。

public final class Message implements Parcelable {
    //...
    Handler target;
    Message next;
    //...
}

每个Message都有一个指向自己的引用,所以它采用链表方式进行存储,如果不考虑Message的事件,如果有新的Message传入,只需要将MessageQueue的最后一个Message的引用指向传入的Message。

3.MessageQueue

MessageQueue 负责管理消息队列,通过一个单链表的数据结构来维护。

这里主要介绍三个方法:

这个方法功能是将消息插入到消息队列中。

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    //在这里使用synchronized同步代码块,防止多线程导致的异步操作混乱。
    synchronized (this) {
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
        //第一部分
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }
        //第二部分
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        //第三部分
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        //第四部分
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; 
            prev.next = msg;
        }
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

这部分主要可以分为四部分。

  1. 如果当前MessageQueue是处于退出状态的,那么要直接返回false,即入队失败。

  2. MessageQueue是根据Message所执行的时间来进行插入的。

  3. 下面即是进行Message链表的插入操作,需要注意的是,MessageQueue中有一个mMessages引用,始终指向Message链表的头节点

  4. 即是一个链表的插入操作。