Handler 源码分析

     为了深入了解Handler,我们对Handler进行源码分析,看看它究竟是如何完成线程间通信的。

从Handler构造出发

     既然是源码分析,为什么突然回到Handler的构造了呢?在我的Handler使用机制及四个组成部分文章中,当我们在非主线程创建handler对象时会出现一个异常。如下:

05-30 15:26:07.490 711-773/com.perry.handler E/AndroidRuntime: FATAL EXCEPTION: Thread-18868
                                                               Process: com.perry.handler, PID: 711
                                                               java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                                   at android.os.Handler.(Handler.java:209)
                                                                   at android.os.Handler.(Handler.java:123)
                                                                   at com.perry.handler.OnBackgroundActivity$2.run(OnBackgroundActivity.java:71)
                                                                   at java.lang.Thread.run(Thread.java:818)

     出现这个问题实际上是因为,handler需要Looper对象,来进行内部的全局变量的初始化。


Handler 源码分析_第1张图片
Handler 构造函数.png
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

     通过查看源码发现,handler共7个构造函数,使用时只能使用4个,最后都会调用执行如上2个构造方法,而这2个构造方法大同小异,所以我们挑个简短的来看看。发现handler需要looper对象来初始化全局变量Looper及MessageQueue,而MessageQueue是从looper中取出的。MessageQueue用于进程间传递消息,Looper则在该线程内进行消息的派发。

handler.sendMessage

     我们通过构造找到了handler的2个协同者,Looper与MessageQueue。那我们发个消息,看看他们都做了些什么!?
     无论调用post方法还是sendMessage方法,handler都会从上到下依次调用如下方法。

sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(Message msg, long uptimeMillis)
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

handler.enqueueMessage

     此时,到了enqueueMessage方法,就证明这条消息确实发送了,该做下一步处理。

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

     该方法中对message设置了target,将当前的handler存于message中,用于之后message找到自己该去的handler,而后将massage交给MessageQueue。调用queue.enqueueMessage(msg, uptimeMillis)方法,将消息放入到消息队列中。强调一下,这里的queue就是我们前面说到的在构造方法中从looper中取到的消息队列。

Looper.loop()

     到了这里,我们发现handler将消息通过MessageQueue放入到消息队列中,那谁把消息取出来进行派发的呢?草丛三兄弟,跳出来两个了,还剩Looper一人默默的蹲在那,那我们来看看他究竟干了啥?!

public static void loop() {
        final Looper me = myLooper();
        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;   
            }
            msg.target.dispatchMessage(msg); // 发送消息, 其中target就是我们之前存入的Handler
        }
    }

     精简了一下该方法,可以看到,Looper通过loop方法,不停的从MessageQueue中取出消息,最终调用了handler的dispatchMessage(msg)方法将消息派发给handler自己。

handler.dispatchMessage

     最后,消息派发给handler,会先判断msg的callback对象(实际上是runnable对象)是否为空,如果不为空则执行handleCallback(msg)方法,callback.run();而如果为空就会调用handleMessage方法,完成回调。(这也是为什么我们构造Handler时,实现了抽象方法handleMessage而post(runnable)时,为什么不调用handleMessage方法的原因)。

// msg.callback实际上是Runnable对象
// mCallback是一个实现了handleMessage(msg)的回调接口
public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg); // msg.callback.run();
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

     那么来画个图总结一下。

Handler 源码分析_第2张图片
Handler 源码分析图示.png

     图中我们从主线程中创建Handler,在子线程中发送消息,而这一系列的配合操作,需要仔细看图,不懂的可以回看文章。
     上一篇: Handler使用机制及四个组成部分

你可能感兴趣的:(Handler 源码分析)