欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android消息机制Handler源码分析

程序员文章站 2022-07-14 18:34:13
...

一. 常用的几种方式

// 方式1
Handler handler = new Handler();
Message message = Message.obtain();
handler.sendMessage(message);

// 方式2
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){...});
复制代码

二. MessageQueue原理

    /**
     * Handler.sendMessage -> Handler.sendMessageDelayed
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    // sendMessage最终会调用sendMessageAtTime这个方法
    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);
    }
    // 将我们创建的这个Message投放到消息队列中去
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
复制代码

好了上面我们看到, 我们创建的Message最后会被投放到消息队列中去, 这个消息队列做了哪些处理呢, 我们跟进入MessageQueue中去看看

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // 若这个Message已经标记为正在被使用, 则抛出异常
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
            msg.markInUse();// 将当前我们传入的Msg标记为正在使用的状态
            msg.when = when;// 该msg发送的时间
            Message p = mMessages;// mMessages为MessageQueue的首元素
            boolean needWake; 
            // 1. 这个if判断是为了确定在未来一段时间里会最先发送的msg, 将其插入到Message链表的首部
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;// 插入到链表首部
                mMessages = msg;// 让mMessage指向链表的首元素
                needWake = mBlocked;
            } else {
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                // 2. 这个for循环从链表的首部开始, 找寻一个适合msg插入的位置, 将其插入到prev的后面和p的前面
                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 (p == null || when == 0 || when < p.when)开始往下的代码就开始了Message的链表操作了 这里我们指定:

  • Message msg1 = Message.obtain(); handler.sendMessage(message);
  • Message msg2 = Message.obtain(); handler.sendMessageDelay(message, 1000);
  • Message msg3 = Message.obtain(); handler.sendMessageDelay(message, 500);
  1. 当我们的消息msg1进入MessageQueue时
    • msg1.when = when; (msg1.when = 0)
    • Message p = mMessages (p = null)
    • ==if (p == null || when == 0 || when < p.when) 显然满足==
    • msg1.next = p; (msg1.next = null)
    • mMessages = msg1
  2. 当我们的消息msg2进入MessageQueue时
    • msg2.when = when; (msg2.when = 1000)
    • Message p = mMessages; (Message p = msg1)
    • ==if (p == null || when(1000) == 0 || when(msg2.when -> 1000) < p.when(msg1.when -> 0)) 不满足条件==
    • Message prev = p; (Message prev = mMessages -> Message prev = msg1)
    • p = p.next; (p = mMessages.next -> p = msg1.next -> p = null )
    • ==if (p == null || when(msg2.when -> 1000) < p.when(null) ) 显然满足条件, break, 退出死循环==
    • msg2.next = p; (msg2.next = null)
    • prev.next = msg2;(mMessages.next = msg2 -> msg1.next = msg2)// 这样就建立了msg1与msg2的链表关系
  3. 当我们的消息msg3进入MessageQueue时
    • msg3.when = when; (msg3.when = 500)
    • Message p = mMessages; (Message p = msg1)
    • ==if (p(msg1) == null || when(500) == 0 || when(msg3.when -> 500) < p.when(msg1.when -> 0)) 不满足条件==
    • Message prev = p; (Message prev = mMessages -> Message prev = msg1)
    • p = p.next; (p = mMessages.next -> p = msg1.next -> p = msg2 )
    • ==if (p(msg2) == null || when(msg3.when -> 500) < p.when(msg2.when -> 1000) ) 显然满足条件, break, 退出死循环==
    • msg3.next = p; (msg3.next = msg2)
    • prev.next = msg3;(msg1.next = msg3) 真是令人惊叹, 我们发送的Message经过这套算法之后, 按照时间发送早晚的顺序链接排序好了

可以看到主要的算法就是使用了一个重要的if判断和一个for循环:

  • if (p == null || when == 0 || when < p.when)
    • 这个if判断是为了确定在未来一段时间里会最先发送的msg
    • 将其插入到Message链表的首部
    • 让mMessages指向链表的首部
  • for (;;)这个for循环从链表的首部开始, 找寻一个适合当前传入的msg插入的位置, 将其插入到prev的后面和p的前面

Summary:

sendMessage方法只是将我们创建的Message投放到消息队列MessageQueue, 这个队列是以链表的方式按照msg发送时间的顺序排列

三. Looper消息循环机制

在线程中无法直接创建Handler

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        // 从Handler的构造方法可知, Handler是无法再直接在子线程中创建的
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        // 这里有个Queue, Nice, This is MessageQueue
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
复制代码

正确创建Handler的姿势如下

    // 在子线程中创建
    Thread({
        // 1. 准备Looper循环
        Looper.prepare()
        Handler()
        Log.e("TAG", Thread.currentThread().toString())
        // 2. 开启循环
        Looper.loop()
    }).start()
    
    // Android的主线程中ActivityThread.class
    public static void main(String[] args) {
        ...
        // 可以看到这里也执行了Looper的prepare方法
        // 我们能在主线程中直接创建Handler肯定也不是凭空来的
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Looper.loop();
    }
复制代码
  1. 分析Looper的prepare方法
    public static void prepare() {
        prepare(true);
    }

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 将我们的Looper set进ThreadLocalMap中
        // static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        sThreadLocal.set(new Looper(quitAllowed));
    }
    
      // 可以看到获取当前线程的Looper是通过sThreadLocal.get()拿到的
     public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }  

复制代码

1.1 刚分析了prepare的源码就发现一个非常重要的ThreadLocal sThreadLocal: static final ThreadLocal sThreadLocal = new ThreadLocal(); 我们跟进去搞清楚

    // ThreadLocal.class 的set方法
    public void set(T value) {
        // 一个线程中有一个唯一的ThreadLocalMap用于存储键值对
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//  ThreadLocalMap map = t.threadLocals;
        if (map != null)
            // key: ThreadLocal, value: T
            map.set(this, value);
        else
            // 给线程创建 ThreadLocalMap 并且将当前的 TheadLocal 和 value 加入其中
            // 一般情况下在线程初始化时会被自动创建
            createMap(t, value);// t.threadLocals = new ThreadLocalMap(this(当前ThreadLocal的实例), value);
    }

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        // 通过跟进源码可知initialValue就是null
        return setInitialValue();
    }

复制代码

可以看到, 我们的sTheadLocal.set(value)方法, 将sThreadLocal和value值set进了ThreadLocalMap中, 这个ThreadLocalMap在一个线程中是唯一的, 而sThreadLocal的value又对应了我们new 的Looper对象, 这样我们就可以通过sTheadLocal.get()方法去获取到我们存入的value了, 这里主要分析Looper相关机制, 对于ThreadLocal存储的细节这里不做深究

  1. 接下来看看Looper.loop做了哪些操作
    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        // 在new Looper()的时候, 会创建一个MessageQueue对象
        // 这里获取到这个MessageQueue对象
        final MessageQueue queue = me.mQueue;
        for (;;) {// 可以看到这里是个死循环
            // 从MessageQueue队列中取出下一个需要执行Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            msg.recycleUnchecked();
        }
    }

复制代码

上述代码中有两行非常值得关注

  • Message msg = queue.next();// 从消息队列中取出当前时间节点需要执行的msg
  • msg.target.dispatchMessage(msg);// 分发这个取出的msg

2.2 看看MessageQueue.next()方法是如何取出msg的

    // 从MessageQueue中取出一下个需要执行的Message
    Message next() {
        ... 
        // 可以看到MessageQueue的next方法也是一个死循环
        for (;;) {
            ...
            synchronized (this) {
                // 尝试从Queue中取出下一个需要执行的Message
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 判断当前Queue首部的Msg是否绑定了Target(Handler), 即判断mMessge是否可用
                if (msg != null && msg.target == null) {
                    // 循环找出当前队里第一个可用的msg
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    // 判断当前时间节点是否大于Msg需要执行的时间
                    if (now > msg.when) {
                        if (prevMsg != null) {
                            // msg即将被取出, 所以它之前的prevMsg的next直接链接上msg的next
                            prevMsg.next = msg.next;
                        } else {
                            // msg即将被取出, 队首元素指向下一个
                            mMessages = msg.next;
                        }
                        // 将这个msg指向的下一个位置置空
                        msg.next = null;
                        // 标记为使用状态
                        msg.markInUse();
                        // 将msg取出, 返回出去
                        return msg;
                    }
                } else {
                    // No more messages.
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }
            }
        }
    }
复制代码

从上面的代码中可以看到Looper.loop中维护了一个for(;;)死循环, MessageQueue.next中也维护了一个for(;;)死循环

  • 第一个死循环的作用是: 循环的从MessageQueue中取出msg, 通过dispatchMessage分发并处理
  • 第二个死循环的作用是: 循环的从MessageQueue中尝试去取出当前可以执行的msg, 将其返回给Loop的loop方法处理并分发

2.3 Handler的dispatchMessage分发处理Msg

    /**
     * Handle system messages here.
     * 终于我们最终还是走到了这个方法中去处理Msg
     */
    public void dispatchMessage(Message msg) {
        // priority1: 处理msg携带的callback
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            // priority2: 处理给Handler设置的mCallback对象中的handleMessage方法
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // priority3: 处理Handler重写的handleMessage(msg)方法
            handleMessage(msg);
        }
    }
复制代码

分析到这里整个安卓的消息机制就明了了, 接下来总结一波

总结

  1. 创建Handler首先要初始化当前线程的Looper, 即Looper.prepare()
  2. 在Looper创建的时, 会创建当前线程的MessageQueue消息队列即Looper.mQueue
  3. 当我们通过Handler在其它线程中发送Message时, 会将其投递到Handler创建线程所在的MessageQueue中
  4. 在Handler创建线程的Looper.loop()方法中, 会不断的循环通过MessageQueue.next()取出当前时间节点需要执行的Message
  5. 取出Message后通过 msg.target.dispatchMessage(msg) 方法分发处理这个Msg, 至此就走到了handleMessage()中