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

Handler消息机制知识点梳理

程序员文章站 2022-07-14 19:59:25
...

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

  • 一个线程之中可以有多个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发送到该消息队列,并在消息出来时执行他们。

Handler有两个用途:

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

往消息队列中发送消息可以通过

为应用程序创建进程时,主线程创建消息队列,该队列负责管理*应用程序对象(活动,广播接收器等)及其创建的任何窗口。您可以创建自己的线程,并通过Handler与主应用程序线程进行通信。这是通过调用与以前相同的post或sendMessage方法完成的。然后,将在Handler的消息队列中调度给定的Runnable或Message,并在适当时进行处理。

MessageQueue

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

1、创建MessageQueue

MessageQueue的创建不需要我们自己去创建,而是通过创建Looper的时候自动创建的,代码如下:

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

由于该构造方法是私有的,所以提供了静态方法prepare()来创建Looper,然后通过myLooper()方法来获取Looper对象,这要是为什么我们在子线程中创建Handler的时候要先调用prepare()方法的原因。

2、Handler发送消息到MessageQueue中

通过调用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;
    }
复制代码

3、处理消息

首先我们要弄明白是谁来进行处理消息的,我们一般创建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之间的关系,还有什么疑问可以留言,如看到一定回解答。感谢阅读????

转载于:https://juejin.im/post/5d54c1b9f265da03b120450e