Android 线程通信 —— Handler 源码

599 阅读4分钟

​ 上篇Android 线程通信 —— Handler 使用说到了 Handler 的使用方法,包括它的 post、send 发送消息的方法,包括它的 Callback、handleMessage 等处理消息的方法。那它是怎么进行消息的管理、怎么把消息通知到对应的线程呢?

​ 上篇说到了组成 Handler 机制的四个主要成员:Handler、Looper、Message、MessageQueue,消息的管理和通知也是主要有它们四个来处理的。

成员备注
HandlerHandler 在其中主要用于发送和处理 Message
Message整个通信机制中消息的载体
MessageQueue每个 Looper 会持有一个 MessageQueue,作为消息队列,Handler 发送的消息都会被放到 MessageQueue 中,MessageQueue 中的消息会根据 when 的长短排列
Looper用于为线程不断从 MessageQueue 中读取 Message 并且交给 Handler 处理,每个线程仅能有一个 Looper,主线程的 looper 在 ActivityThread 的 main() 中被创建,子线程需要我们手动创建

我们可以从上篇文章所说到的最后 enqueueMessage 方法看起:

// sendMessageAtTime() 使用的是 enqueueMessage()
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    // mQueue 是 Handler 持有的 mLooper 持有的,在构造方法里做了个引用
    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);
}

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 可以看到,最后是调用了 MessageQueue 的 enqueueMessage()
        return queue.enqueueMessage(msg, uptimeMillis);
    }

​ 我们可以 Handler 发送的 Message 都放到了 MessageQueue 中,那 MessageQueue 是如何持有消息的呢?MessageQueue 其实是一个链表结构,持有一个 mMessage 作为头结点,而 Message 有 next 节点,一串的 Message 就组成了 MessageQueue,我们来看看 MessageQueue 是如何存放 Message 的:

boolean enqueueMessage(Message msg, long when) {
        ...
        synchronized (this) {
            ...
            // 将 delay 时间 when 赋值给 msg
            msg.markInUse();
            msg.when = when;
            // 获取当前头结点的 Message
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // 如果没有头结点或者延时为 0,或者延时小于头结点的延时,就将新的 Message 置为头结点
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                // 如果 MessageQueue 中还有消息,或者插入的 Message 的 when 不为 0,就遍历链表,根据 when 的长短,将 Message 插入到对应的位置
                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;
    }

我们可以看到存放 Message 的逻辑并不是很复杂,就是如果 MessageQueue 中没有消息,就将新消息作为头结点,如果 MessageQueue 中有消息,就根据每个 Message 的 when 由短到长插入。

放完了 Message,那么怎么取呢?这里就要用到 Looper 了。我们知道,在子线程中使用 Handler,我们需要主动创建 Looper 并且调用 Looper.loop(),其实 Looper.loop() 就是在不断的从 MessageQueue 中取出消息并且交给 Handler 的 dispatchMessage() 处理的过程:

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 (;;) {
            // 一直 for 循环,从 MessageQueue 中取 Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            ...
            try {
                // 然后交给 Handler 的 dispatchMessage 处理,在使用 Handler 发送非屏障 Message 时,Handler 会把 this 赋值给 Message 的 target
                msg.target.dispatchMessage(msg);
                
                ...
            } catch (Exception exception) {
                ...
            } finally {
                ...
            }
          
            ...

            msg.recycleUnchecked();
        }

那么 MessageQueue 是怎么通过 next() 来取 Message 的呢?

Message next() {
        // 一直 for 循环遍历
        for (;;) {

            //休眠到下一个 msg 的 when 时间,下面有计算该时间,插入消息也会唤醒
            nativePollOnce(ptr, nextPollTimeoutMillis);
          
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // msg 的 target 为 Handler,如果为空,则表示这是个同步屏障,则 while 循环找到第一个异步消息
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 如果有内存屏障现在的消息为第一个异步消息,否则为第一个消息
                if (msg != null) {
                    if (now < msg.when) {
                        // 还没到第一个消息的 when,则拿到需要休眠的时间,在上面 for(;;) 开始时,休眠到 msg 准备好
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 正常返回第一个消息,并且将头指针指向下一个消息
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        // 返回消息
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
                ...
        }
    }

我们看到是怎么取消息的,也知道取完消息会交给 Handler 的 dispatchMessage() 方法处理,那么 dispatchMessage() 干了什么呢?

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        // msg 有 callback 就直接走 message.callback.run()
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            // 如果重写 Handler 的 callback 的 handleMessage 返回 true,就只走 callback 的 handleMessage,否则 Handler 和 callback 的 handleMessage 都会走
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

Handler 的大致通信流程就是这样,但是 Handler 的相关知识并没有结束,比如上面提到的内存屏障、异步消息、Looper 的创建和存取、ThreadLocal等,还有很多需要我们去了解的,争取下一篇放出来。

更新太慢了,太懒了,每天下班11点到家,完全不想看,不想写。。。 努力继续记录吧