Android消息机制浅析(不做标题党)

本文主要介绍Android的消息机制,而了解消息机制必先了解Handler,Looper,MessageQueue。

Android的消息机制主要是Handler的运行原理,弄清楚了Handler是如何运行的也就大致清除了Android的消息机制是如何运行的。而Handler内部中又紧紧包含了Looper和MessageQueue,因此我们可以根据Handler源码依次顺藤摸瓜,弄清Looper和MessageQueue原理,从而明白消息机制。但我们需要先了解Handler,Looper,MessageQueue,Message是什么。

文章出自:Android消息机制浅析

Handler

为了了解Handler,我们先来看一下Handler的初始化函数做了哪些操作。

    public Handler(Callback callback, boolean async) {
        ......
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

可以看到Handler中存储了当前线程的Looper,同时可以看到如果该线程中如果没有Looper的话,创建Handler的时候便会抛出异常。Handler中除了Looper,还存储了Looper中的消息队列。

Looper

在Handler的构造函数中我们看到了获取了Looper对象存入其中,那我们先来看下myLooper是怎么获取的。

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

此处的sThreadLocal 是一个ThreadLocal对象,存储着当前线程的Looper。ThreadLocal是一个在线程之间存储数据的类。内部采用了Map映射的方法。<key(当前线程), Value(存储的数据)>

MessageQueue

消息队列其实并不是采用数据结构中的队列来实现的,采用了一个单链表的形式来存储消息的。MessageQueue中有一个Message类型的局部变量mMessage,是一个单链表的形式来存储消息的。

消息传递流程

Handler 有两种方式可以向MessageQueue 发送消息,一种是post ,另外一种是sendMessage。但其实post 实际上也是通过sendMessage来发送消息的。我们可以来看下源码。

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

我们可以看到Runnable 通过getPostMessage来将Runnable封装成了一个Message 然后再发送出去。我们再来看下sendMessage

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

sendMessage直接将message 发送出去,而post 我们通过源码查看,发现其本质也是和sendMessage一样发送Message。所以我们可以再来看一下Handler 如何发送消息。

    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);
    }

Handler 最终调用sendMessageAtTime来发送消息的,我们可以看到其实Handler只执行了enqueueMessage函数,我们再来看下这个函数。

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

这个函数把Handler 存进了Message中的target中了,然后将message插入了消息队列中。我们紧接着到MessageQueue文件中看下enqueueMessage代码。

    boolean enqueueMessage(Message msg, long when) {
        ......
        synchronized (this) {
            ......
            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;
    }

在if else 中的判断中,if 中如果消息队列中没有消息了,那么将我们插入的消息作为消息头,并且需要去唤醒Looper。在else 中则是将msg插入到队列尾部。(因为本人算法不好,所以是用笔写写来理清的else中的逻辑)enqueueMessage执行完之后消息便插入MessageQueue的尾部了,所以接下来我们要看一下Looper中loop是如何从MessageQueue中取出消息来处理的。

    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
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ......
            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ......
            msg.recycleUnchecked();
        }
    }

loop中从当前Looper 的消息队列中不断拿消息,然后将消息丢给msg.targetdiapatchMessage来处理,而之前Handler 的enqueueMessage中有介绍过,Handler 把数据给消息队列之前将自己存入了Message 的 target 中,所以此处是把消息给发送它的Handler来处理,这样消息的处理就转移到了创建Handler的线程中来了。(而我们的Handler一般都是通过getMainLooper来创立的,即主线程的Handler,即将消息传入到主线程来处理了)

接着,我们再来看下Handler 是如何处理消息的。

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

首先看消息中的callback是不是空,而我们有说过Handler post Runnable的时候我们有通过getPostMessage把Runnable封装成消息,封装的时候就将Runnable存入了消息的callback中,所以此处消息中的callback就是我们之前post的Runnable对象,在handlerCallback中我们看到将Runnable运行在了主线程。 另外一种情况,如果我们是直接发送消息的那么我们就会调用mCallback.handlerMessage来处理消息,而handleMessage为我们创建Handler的时候重写的函数,这样也将消息在主线程中处理了。

至此,我们已经从Handler发送消息到MessageQueue,然后Looper从MessageQueue中取消息进行处理的全部流程都梳理了一遍,这也就是Android消息机制的运行主线。文中可能有些讲解不当的地方,烦请大家指教。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值