Android源码阅读:Handler机制

一、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) {
    }

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值