Handler消息机制知识点梳理

在阅读该篇文章以前要清楚的一些知识点:html

  • 一个线程之中能够有多个Handler,可是每一个线程之中只有一个Looper和一个MessageQueue
  • 消息队列MessageQueue是在Looper中进行建立的,Handler的做用是往MessageQueue中发送消息和处理消息的
  • 在子线程中若是要建立Handler对象,必须先调用Looper.prepare()方法建立Looper对象和MessageQueue
  • 在什么线程中建立Handler,那么该Handler就持有该线程的LooperMessageQueue,例如在主线程中建立Handler就能够更新UI界面就是由于这个

官方说明

Handler容许你发送和处理Message消息,每一个Handler的实例都与一个线程和该线程中的消息队列(MessageQueue)关联,当你建立一个新的Handler时,它就绑定到了正在建立它的线程(消息队列),而后就能够经过该Handler将Message和runnables发送到该消息队列,并在消息出来时执行他们。java

Handler有两个用途:android

  • 安排消息(Message)和runnables在未来的某个时刻执行
  • 线程之间的通讯

往消息队列中发送消息能够经过多线程

为应用程序建立进程时,主线程建立消息队列,该队列负责管理顶级应用程序对象(活动,广播接收器等)及其建立的任何窗口。您能够建立本身的线程,并经过Handler与主应用程序线程进行通讯。这是经过调用与之前相同的post或sendMessage方法完成的。而后,将在Handler的消息队列中调度给定的Runnable或Message,并在适当时进行处理。async

MessageQueue

官方文档中屡次提到了MessageQueue这个消息队列,那么该消息队列何时建立的,Handler怎么发送消息到MessageQueue中的,以及怎么处理这些消息的?下面经过源码的方式梳理这个流程.ide

一、建立MessageQueueoop

MessageQueue的建立不须要咱们本身去建立,而是经过建立Looper的时候自动建立的,代码以下:post

private Looper(boolean quitAllowed) {
        //在Looper的构造方法中,建立了MessageQueue
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
复制代码

因为该构造方法是私有的,因此提供了静态方法prepare()来建立Looper,而后经过myLooper()方法来获取Looper对象,这要是为何咱们在子线程中建立Handler的时候要先调用prepare()方法的缘由。ui

二、Handler发送消息到MessageQueue中this

经过调用Handler的 post sendMessage等方法能够将消息发送到MessageQueue中,具体中间经历了什么,全部的post方法和sendMessage方法,最终调用的都是sendMessageAtTime方法能够看一下源代码:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //获取到消息队列,消息队列是在Handler的构造方法中获取到的
        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的时候,构造方法中会获取当前线程的Looper,而后经过Looper获取到MessageQueue.

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());
            }
        }
        //获取该线程的Looper对象,Looper对象是放在ThreadLocal对象中的,保证每一个线程只有一个Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //获取了消息队列,在sendMessage和post的最后都是往队列中插入消息
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
复制代码

三、处理消息

首先咱们要弄明白是谁来进行处理消息的,咱们通常建立Handler的时候会重写一个方法handleMessage, 若是是经过post(Runnable run)的方法发送的消息,处理是在handleCallback的方法中,不须要本身去实现。

那么是何时调用的handleMessage方法呢?

  • 应用启动以后,主线程开启Looper循环,调用Looper.loop()方法开启死循环,该循环中就是从MessageQueue中取消息来处理,若是没有消息了会阻塞。释放CPU资源
public static void loop() {
        final Looper me = myLooper();
         //...省略部分代码...
        //开启死循环
        for (;;) {
            //从消息队列中获取Message,该方法会阻塞,若是队列中没有消息,则阻塞,释放CPU资源
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            
           //...省略部分代码...
           

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                //target就是这个消息是哪个Handler发送的,target就是那个Handler对象,
                //调用Handler的dispatchMessage方法来派发消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           //...省略部分代码...
            //消息回收
            msg.recycleUnchecked();
        }
    }
复制代码
  • loop()方法中找到了消息发送到MessageQueue的时候,Looper会从消息队列中获取到消息,而后经过消息中的target字段获取到消息所属的Handler,而后调用HandlerdispatchMessage来进行处理。
/** * Handle system messages here. */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
复制代码

从上面的方法中能够看到,若是callback不为空,就直接执行handlerCallback,callback其实就是一个Runnable , handleCallback方法就是调用run())方法来使其运行。 若是callback为空的状况下就是经过handleMessage来进行处理消息了。因此咱们在建立了Handler的时候要重写该方法进行一些操做

总结

以上基本上就是Handler的一些流程说明了,如今咱们不多用到Handler,可是不少线程的切换底层仍是用到的Handler, 这是基础。因此仍是须要了解一下。文中也有说明了Looper HandlerMessageQueue之间的关系,还有什么疑问能够留言,如看到必定回解答。感谢阅读🤝

相关文章
相关标签/搜索