美文网首页
Android源码阅读:Handler机制

Android源码阅读:Handler机制

作者: BlueSocks | 来源:发表于2024-01-02 19:38 被阅读0次

    一、Handler机制概述

    接触Android的人都会很快使用到Android中的Handler机制,最常见的应用场景是子线程更新UI线程的问题。
    Handler机制是一种生产者-消费者模型,其中Handler作为生产者,将消息发送到MessageQueue,MessageQueue底层是由链表实现的,Looper作为消费者,源源不断地从MessageQueue中拉取新的消息。注意Looper虽然是消费者的角色但自身并不对消息做处理,可以理解为Looper代表了消息的目标线程,其拉取消息后分发到对应的Handler(其实就是发送消息的Handler)去处理,这个过程实现了跨线程处理。

    二、Looper和Handler的构造

    1、Looper的构造

    要想让一个普通线程能够使用Handler机制处理消息,必须先调用Looper.prepare(),再调用Looper.loop()

    frameworks/base/core/java/android/os/Looper.java

    public final class Looper {
    
        final MessageQueue mQueue;
        final Thread mThread;
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
        
        
        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));
        }
    
    }
    
    

    从Looper源码中可以看到,prepare函数实际上是利用ThreadLocal在调用的线程中构造一个独一无二的Looper。
    而在Looper的构造函数中,会创建一个新的MessageQueue。
    因此可见,一个Looper对应一个MessageQueue,一个线程有且仅能有一个Looper,也仅能有一个MessageQueue。

    2、Handler的构造

    Handler的构造可以指定Looper并保存在mLooper中,代表了使用这个Handler发出的消息,能够在指定Looper的线程中被处理。

    public class Handler {
    
        final Looper mLooper;
        final MessageQueue mQueue;
    
        public Handler() {
            this(null, false);
        }
        public Handler(@Nullable Callback callback, boolean async) {
            mLooper = Looper.myLooper(); 
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
        }
    
        public Handler(@NonNull Looper looper) {
            this(looper, null, false);
        }
        public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    
    
    

    缺省情况下mLooper通过Looper.myLooper()获取,实际是获取当前线程的Looper。
    frameworks/base/core/java/android/os/Looper.java

        /**
         * Return the Looper object associated with the current thread.  Returns
         * null if the calling thread is not associated with a Looper.
         */
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    
    

    因此可知,一个Handler只对应一个Looper,但多个Handler可以用同一个Looper初始化,即一个Looper可以对应多个Handler,一个线程也可以有多个Handler。

    综上,可以有多个生产者(Handler),多个生产者可以向同一个MessageQueue发送消息。
    但由于MessageQueue是随Looper创建而创建的,和Looper一一对应,Handler机制通过ThreadLocal限制了一个线程仅能有一个Looper,因此一个MessageQueue也仅能有一个Looper消费消息。

    一中有讲Looper虽然作为消费者,但并不处理消息,而是分发到Handler去处理,这又是怎样的过程呢?需要从发送消息看起。

    三、Handler发送消息后的流程

    1、Handler发送消息

    Handler可以通过post或者sendMessage系列函数发送消息,最终都是调用到sendMessageAtTime函数
    frameworks/base/core/java/android/os/Handler.java

        public final boolean post(@NonNull Runnable r) {
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
        public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
            return sendMessageAtTime(getPostMessage(r), uptimeMillis);
        }
    
        public final boolean sendMessage(@NonNull Message msg) {
            return sendMessageDelayed(msg, 0);
        }
    
        public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    
        public boolean sendMessageAtTime(@NonNull 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);
        }
    
    

    而sendMessageAtTime函数则是调用enqueueMessage向Handler对应的队列插入消息

        private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
                long uptimeMillis) {
            msg.target = this;
            msg.workSourceUid = ThreadLocalWorkSource.getUid();
    
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
    

    Handler的enqueueMessage函数有一个操作值得注意,就是将自身引用保存到msg.target,这里为之后消息的分发埋下伏笔。
    最终调用MessageQueue的enqueueMessage函数。

    2、消息插入MessageQueue

    MessageQueue是使用链表实现的。
    代码略去部分内容,核心逻辑是根据目标时间将消息插入到MessageQueue中正确的位置。
    frameworks/base/core/java/android/os/MessageQueue.java

        boolean enqueueMessage(Message msg, long when) {
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target."); // msg必须指定Handler
            }
    
            synchronized (this) {
    
                msg.markInUse();
                msg.when = when; // when是对应的upTime,注意这里是upTime,不包括idle时间
                Message p = mMessages; // mMessages指向消息队列链表第一个元素,这里给赋值给临时变量p
                boolean needWake;
                if (p == null || when == 0 || when < p.when) { // 链表为空,或者新msg目标时间比较早的情况下
                    // New head, wake up the event queue if blocked.
                    msg.next = p; // 新来的msg直接放在链表头
                    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(); // p.target是msg对应的 Handler
                    Message prev;
                    for (;;) {
                        prev = p; // 从链表头部开始遍历
                        p = p.next;
                        if (p == null || when < p.when) { // 根据msg的目标时间找到正确位置 断开链表,msg应该放在 prev和p的中间
                            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); // mPtr是一个给native代码用的Long
                }
            }
            return true;
        }
    
    

    至此,可以知道Handler发送消息之后,就是将消息根据目标执行时间,插入到MessageQueue中正确的位置。
    那么消息是怎么被处理的呢?

    四、Looper处理消息的流程

    1、消息的获取

    前面有说线程使用Looper必须先调用Looper.prepare(),再调用Looper.loop()
    loop函数就是用来循环从MessageQueue中取出消息的,代码核心逻辑可以简化为:
    frameworks/base/core/java/android/os/Looper.java

        public static void loop() {
            final Looper me = myLooper();
    
            for (;;) {
                if (!loopOnce(me, ident, thresholdOverride)) {
                    return;
                }
            }
        }
    
        private static boolean loopOnce(final Looper me,
                final long ident, final int thresholdOverride) {
            Message msg = me.mQueue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return false;
            }
    
            try {
                msg.target.dispatchMessage(msg);
            }
    
        }
    
    

    loop()函数中主要是循环调用loopOnce直到返回false,而在loopOnce函数中则是通过MessageQueue的next函数获取消息,再进行分发。
    next()的核心逻辑可以简化为:
    frameworks/base/core/java/android/os/MessageQueue.java

        Message next() {
            for (;;) {
                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?
                        // 前面看enqueueMessage确认进来的msg都是有target的,那么这个没有target的msg怎么进来的呢?
                        // Stalled by a barrier.  Find the next asynchronous message in the queue.
                        // 被barrier拦住了。 查找队列中的下一条异步消息。
                        do {
                            prevMsg = msg;
                            msg = msg.next;
                        } while (msg != null && !msg.isAsynchronous());
                    }
                    // 到这里,msg变成了队列中的第一条异步消息
    
                    if (msg != null) {
                        if (now < msg.when) {
                            // Next message is not ready.  Set a timeout to wake up when it is ready.
                            // 下一条消息尚未准备好。 设置一个超时,以便在准备就绪时唤醒。
                            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                        } else {
                            // Got a message.
                            mBlocked = false;
                            if (prevMsg != null) {
                                prevMsg.next = msg.next; // 把msg从队列中取出,然后把 前一个prev和下一条 重新连接起来
                            } else {
                                mMessages = msg.next; // 没有prev,那么队首就等于msg的下一条
                            }
                            msg.next = null;
                            if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                            msg.markInUse();
                            return msg; // 这里可以理解为,只要msg的目标时间,小于等于now,那么就会被Looper用Msg Queue的next()取出来
                        }
                    }
                }
            }
        }
    
    

    next()函数中,获取当前的upTime,消息队列中的消息经过遍历,早于当前时间的消息被从链表中取出,时间未到则进入休眠等待唤醒。

    2、消息的分发和处理

    loopOnce函数中,获取的消息会调用msg.target.dispatchMessage(msg),在消息入队时,Handler将自身引用保存到了消息的target中,因此这里调用的是:
    frameworks/base/core/java/android/os/Handler.java

        /**
         * Handle system messages here.
         */
        public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    
    

    在消息存在callback时调用handleCallback,否则看Handler创建时是否指定Callback,均没有则调用handleMessage进行处理。消息的处理通常是实现一个Handler子类并重写handleMessage函数,或者实现Callback接口。
    frameworks/base/core/java/android/os/Handler.java

        public interface Callback {
            /**
             * @param msg A {@link android.os.Message Message} object
             * @return True if no further handling is desired
             */
            boolean handleMessage(@NonNull Message msg);
        }
        
        /**
         * Subclasses must implement this to receive messages.
         */
        public void handleMessage(@NonNull Message msg) {
        }
    
    

    相关文章

      网友评论

          本文标题:Android源码阅读:Handler机制

          本文链接:https://www.haomeiwen.com/subject/uqxmndtx.html