Message 机制 (java 层)

前言

Message 机制作为一种系统通信机制,主要涉及到了以下几个部分(java 层):

  • Handler.java
  • Looper.java
  • Message.java
  • MessageQueue.java

其被广泛应用于系统和应用的各处,例如:

        Message msg = mWorkerHandler.obtainMessage(MSG_HANDLE_PKG_EVENT, event);
        mWorkerHandler.sendMessage(msg);

下面我们就来看一看它是怎样实现通信的,以及其究竟干了什么。

一、Message 的添加

1.1 obtainMessage

1.1.1 Handler.obtainMessage

Handler.java

    public final Message obtainMessage(int what, Object obj)
    {
        return Message.obtain(this, what, obj);
    }

1.1.2 Message.obtain

Message.java

    public static Message obtain(Handler h, int what, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.obj = obj;

        return m;
    }

由此可知,obtainMessage 的作用是:

  • 调用 Message 的 obtain() 方法得到一个 Message 对象
  • 对 Message 对象的各个成员变量进行赋值,其中 target 即被赋值为调用 obtainMessage 的 Handler 对象,即 mWorkerHandler

1.1.3 Message.obtain()

Message.java

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

从上面看来,obtain() 会检查 sPool 这个 Message Pool 是否为空,如果不为空则从头部取出一个 Message 对象,如果为空则返回一个新构建的 Message 对象;
下面再来考虑一个问题:此处的 sPool 是什么?

1.1.4 Message.sPool

Message.java

    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;

    /* 回收 Message */
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                ...
            }
            return;
        }
        recycleUnchecked();
    }

    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                // 把 this 插入到 sPool 中
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

由此可见:

  • sPool 是由我们之前创建后回收的 Message 对象填充起来的
  • FLAG_IN_USE 这个 FLAG 在被 recycle 和 enqueueMessage 时都会被标记;并且在被 recycle 时,Message 对象其他信息会被清空

sendMessage

1.2.1 Handler.sendMessage

Handler.java

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

1.2.2 sendMessageDelayed

Handler.java

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

把 delayMillis 转化为 SystemClock 时间

1.2.3 sendMessageAtTime

Handler.java

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

这里我们先留一个疑问: mQueue 是什么?

1.2.4 enqueueMessage

Handler.java

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        // 这里又会对 msg.target 附一次值
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 调用 MessageQueue 的 enqueueMessage 方法
        return queue.enqueueMessage(msg, uptimeMillis);
    }

1.3 enqueueMessage

1.3.1 MessageQueue.enqueueMessage

MessageQueue.java

    boolean enqueueMessage(Message msg, long when) {
        ...
        synchronized (this) {
            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 {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

这里主要是按照插入 mMessages 头部和插入 mMessages 中两种情况将传过来的 Message 对象插入 mMessages 队列中
下面我们来看一下 mMessages 队列中的 Message 是怎么被处理的。

二、Message 的分发

以开头的程序示例为例,我们来看一下 mWorkerHandler 是怎么初始化的:

mHandlerThread = new HandlerThread("String ...", Process.THREAD_PRIORITY_BACKGROUND);
// 会启动一个新线程,并在新线程中运行run()方法
mHandlerThread.start();
mWorkerHandler = new EventWorkHandler(mHandlerThread.getLooper());

public class HandlerThread extends Thread {
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
}

2.1 Looper

2.1.1 Looper.prepare()

Looper.java

    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

由此可知,mQueue 指向 Looper 对象自己的 MessageQueue,mThread 指向 Looper 对象所在的线程

2.1.2 Looper.loop()

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        ...
        for (;;) {
            // 取出下一个需要处理的 Message,涉及到 native 层,暂不讨论
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            // 调用目标 Handler 的 dispatchMessage 方法
            msg.target.dispatchMessage(msg);
            msg.recycleUnchecked();
        }
    }

可以看出 loop() 方法就是不断地循环,对其 MessageQueue 中的 Message 进行处理。

2.2 Handler

2.2.1 Handler 的初始化

我们再来看一下 1.2.3 中所留的疑问:mQueue 是什么?

    public Handler(Looper looper) {
        this(looper, null, false);
    }

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

由此可知:Handler 中 mQueue 所指的队列其实就是 Looper 初始化时为自己创建的 MessageQueue

2.2.2 Handler.dispatchMessage

Handler.java

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

由此可以看出,dispatchMessage 做了如下事情:

  • 如果 Message 有 callback,则执行 callback 的 run() 方法
  • 如果 Message 没有 callback
    • 如果 Handler 有 mCallback,执行 mCallback 的 handleMessage() 方法
    • 执行 Handler 的 handleMessage 方法

总结

3.1 各组件结构图

这里写图片描述

上图列出了 Message 机制涉及到的主要的类以及他们之间的关系:

  • Looper 内部有 mQueue 和 mThread 两个成员,分别指向其构建的 MessageQueue 和其所在的 Thread
  • MessageQueue 中保存了一个 Messages 组成的队列 mMessages
  • Message 中的 target 指向用 Looper 构建的 Handler
  • Handler 中的 mLooper 和 mQueue 分别指向初始化时传过来的 Looper 以及 Looper 中的 mQueue

因此,Message 的处理(handleMessage 等)是在 Handler 的 Looper 所在的线程中完成的

3.2 Message 机制的工作

  • Looper 一直在循环,从其 mQueue 中取出 Message 并调用目标 Handler 的 dispatchMessage 方法(Message 的分发)
  • 构建 Message,并通过 sendMessage 等方法将其添加到 MessageQueue 中(Message 的添加)

3.3 Message 的创建

Message 主要包含以下内容:

数据类型 成员变量 含义
int what 消息代号
long when 消息触发时间
int arg1 参数1
int arg2 参数2
Object obj 消息内容对象
Handler target 目标 Handler
Runnable callback 回调方法


创建 Message 的过程,就是填充 Message 的上述内容的一项或多项的过程

猜你喜欢

转载自blog.csdn.net/u013989732/article/details/78135947