Android源码阅读之Handler

Android源码阅读之Handler

从 handler.sendMessage() 入手,了解 Handler 处理 Mesage 的流程

handler 处理机制虽然看多很多遍,但每一次重读都能加深印象。

handler 常用的两个构造方法:

    public Handler() {
        this(null, false);
    }
    public Handler(@Nullable Callback callback) {
        this(callback, false);
    }

两个构造方法最终都调用了一个隐藏的构造函数,Callback 是处理 Message 的回调,第二个值 false 含义是标志此 Message 是否为一个异步消息

Message 的创建与发送

创建一个 Message 一般直接 new 构造函数即可,但一般来说推荐使用 obtain() 方法,它省略了创建对象的过程,从之前已经销毁的队列中取出一个。

obtain() 中取得 Message 的队列一般是 50 个,由: MAX_POOL_SIZE 决定

    public Message() {
    }

当设定 message 的 what obj 之后,调用 handler.sendMessage(Message msg) 方法即可。

在这个方法内部,会将 Message 绑定到当前的 handler

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

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        ......
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        ......
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    // 在将 Message 加入 链表前,会绑定 msg.target = this
    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);
    }

MessageQueue 是什么?

MessageQueue 对象用来存储 Message,根据名称,可以翻译为 消息队列,但实际上,它是通过链表结构存储 Message 的

它在 Handler 的构造函数中获取:mQueue = mLooper.mQueue; 。通过构造函数中的这行代码,可以看到是从 Looper 中得到的。

在 Looper 中,它会在调用 Looper.prepare() 方法后创建:

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


    private static void prepare(boolean quitAllowed) {
        ......
        sThreadLocal.set(new Looper(quitAllowed));
    }

    // 在私有构造函数中创建
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

MessageQueue 对象的 enqueueMessage 方法中,会从头遍历这个链表结构,并将 msg 插入到合适的位置

    boolean enqueueMessage(Message msg, long when) {
        ......
        synchronized (this) {
            ......
            if (p == null || when == 0 || when < p.when) {
                // 如果当前链表结构为空,或头部的节点时间大于当前节点时间
                // 则直接插入到链表头部
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // 否则遍历链表结构,插入合适的地方
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    // 使用 for 遍历链表,并判断待插入的 msg 的时间(也就是 when 的值)是否小于链表中当前节点的时间
                    //如果待插入的 msg 的时间小于 当前节点的时间,则跳出
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                // 在这里,将待插入的 msg 插入到链表结构中
                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 插入链表结构的代码逻辑。这个链表结构是通过 when 属性,也就是执行的延迟时间来排序的

当需要执行一个 Message 时,头部的 Message 总是最先取到的。

Message 的消费

Message 是通过 Looper 来消费的。在调用 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 msg = queue.next(); // might block

            ......

            msg.target.dispatchMessage(msg);

            ......

            msg.recycleUnchecked();
        }
    }

loop() 方法会不断从链表结构取得一个 Message ,并进行一些判断。然后调用 msg.target.dispatchMessage

msg.target 就是之前绑定的 Handler

所以消息的处理会回到 Handler 中的 dispatchMessage 方法

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

msg.callback 是什么?

Handler 源码中,有一个方法对 msg.callback 进行赋值:

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

它是一个 Runnable 对象,如果调用 handler.post() 执行一个线程,那么就会对 callback 进行赋值

mCallback 便是创建 Handler 对象时,传入的 Callback。如果创建 Handler 时,没有传入 Callback 对象,则默认使用 Handler 的方法 handleMessage 。也就是 Handler 如果需要处理 Message ,需要传入 Callback 或者实现 handleMessage 方法

至此,Message 对象的创建与消费流程已经完成了。

Looper.loop() 方法还有一个妙用。可以 post 一个 message。这个 message 中再调用 Looper.loop() ,这样可以使用 try catch 包裹这个方法调用。实现主线程的错误捕获。


Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://zwc365.com/2020/11/16/android源码阅读之handler

Buy me a cup of coffee ☕.