我对Handler机制的理解

太心塞了,刚写了好几个小时总结好的,准备发表时候因为CSDN页面突然崩掉,搞得之前写了两个多小时的东西突然就没了,这倒是给了自己一个教训,以后写文章还是得用工具写,目前用的印象笔记,使用马克飞象支持MarkDown,也还是蛮好用的,废话不多说了,又得重新写一遍了,心塞塞

之前写过一篇对于源码的分析,有兴趣的可以看看Handler源码分析,现在这篇文章主要是为了自己总结好语言,方便面试的时候能说的通,不然面试的时候总是很含糊。

Handler消息机制是由Handler、Looper、MessageQueue、Message等组成的,它一般用来解决子线程中无法更新UI的问题(子线程中更新UI不一定会有问题,Android中子线程真的不能更新UI吗?),线程默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。我们经常提到的主线程,也叫UI线程,它就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是在主线程中默认可以使用Handler的原因。所以,Handler机制的前提是要先有Looper,那么我们就先从Looper看起,看看Looper是如何创建的,创建时有什么特征?

一、Looper初始化

Looper初始化只能通过Looper.prepare()方法进行初始化,在Looper.prepare()方法中,首先会通过ThreadLocalget()方法来获取一个Looper对象,如果获取到的值为null,则会new一个Looper实例并通过ThreadLocalset()方法来将该实例对象存储在当前线程内部,否则会抛出异常,这也表示在一个线程中Looper.prepare()方法只能执行一次,即也只存在一个Looper。 看下源码:

 private static void prepare(boolean quitAllowed) {
        //ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据
        //数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说无法获取到数据
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

二、MessageQueue初始化

通过上面我们知道了一个线程中最多只存在一个唯一的Looper对象,且每个线程中需要调用Looper.prepare()方法才会有实例化Looper对象(主线程在ActivityThread的main()方法中自动帮我们调用了Looper.prepare()方法),那么MessageQueue是在哪里初始化的呢?我们先看下Looper的构造函数:

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
}

答案显而易见了,MessageQueue是在Looper的构造函数中创建的,前面说了,在一个线程中最多只存在一个Looper,那么同样的,一个线程中最多只存在一个MessageQueue。且由于主线程中系统已经自动为我们调用了Looper.prepare()方法,所以在主线程中一定存在一个唯一的Looper与MessageQueue。

三、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;
 }
public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
}

在Handler构造函数中我们通过ThreadLocal.get()方法获取到了当前线程的Looper与MessageQueue(假如当前线程调用了Looper.preapare()方法),这样Handler中就有了当前线程的Looper、MessageQueue。

四、Handler.sendMessage(msg)

通过前面的分析我们知道了在Handler初始化的时候获取到了当前线程的Looper与MessageQueue,那么现在我们假设在主线程中创建了Handler:

 private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {//主线程中执行
            super.handleMessage(msg);
        }
    };

然后在子线程中发送了一条Message:

new Thread(new Runnable() {
            @Override
            public void run() {
                mHandler.sendMessage(new Message());
            }
        }).start();

我们知道在子线程中发送的Message会在handleMessage(Message msg)方法中回调,但是其具体是如何实现的,这才是我们要分析的:
1. 首先我们先看mHandler.sendMessage(new Message());,该方法最终会将自身(Handler)赋值给了Message.target,然后调用MessageQueue的enqueueMessage(msg, uptimeMillis)方法用来将Message发送到MessageQueue中。这样就将Message插入到了MessageQueue中。

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
  1. 既然Message被插入到了MessageQueue中,那么又是如何被Handler回调处理的呢?这里就涉及到了Looper.loop()方法,Looper.loop()方法通常是与Looper.prepare()方法成对出现的,该方法源码较长,就不贴了。其主要的实现逻辑为:通过在一个无限循环的for循环中调用MessageQueue.next()方法获取MessageQueue中的每一条Message,接着调用了 Message.target.dispatchMessage(msg);方法,前面我们说了在sendMessage()时将Handler赋值给了Message.target,所以,这里的Message.target.dispatchMessage(msg);调用的就是我们Handler.dispatchMessage(msg)方法,这样消息就回调到了我们的Handler中

  2. 那么现在我们来看看Handler.dispatchMessage(msg)方法中做了什么处理:

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

这就一目了然了吧!虽然前面有一些判断,但是我们还是可以看到其中有调用到我们的handleMessage(msg)方法,这就实现了在子线程中发送的Message在主线程中回调的一个过程。至于前面有一些判断是用来处理Handler.post()更新UI时用到的,具体可以看前面的源码篇。

最后关于Handler的一些扩展介绍:Android 消息机制——你真的了解Handler?

猜你喜欢

转载自blog.csdn.net/xiaochao_develop/article/details/82432781
今日推荐