27
2017
09

最简洁的Handler、Looper、Message源码级原理分析

每一个Android开发者,基本都能把Handler、Looper、Message的原理说上一通,最基本的面试题答案“每个线程里可以创建一个Looper,Looper里维护一个消息队列,handler可以往这个消息队列发消息,Looper又不停的从消息队列里取出消息分发给对应的handler”。然而实际上很多开发者对这段话只是一知半解,在这篇博客里,我来用最简洁的语言,梳理一遍Handler、Looper、Message相关的源码。(以下代码都是经过简化或修改的,只包含关键代码逻辑,与实际android源码有所不同

先看一下创建一个新线程,并且创建一个handler的基本代码。

new Thread() {
    @Override
    public void run() {
        Looper.prepare();
        mHandler = new Handler();
        Looper.loop();
    }
}.start();

一共就三句,Looper.prepare(); mHandler = new Handler(); Looper.loop(); 一句句来分析。

public static void prepare() {
    sThreadLocal.set(new Looper());
}

prepare方法非常简单,只是new了一个Looper,放到ThreadLocal里。(再次注明,本篇列出的代码都是经过简化修改的,只列出了关键代码逻辑,真实android源码有所不同

private Looper() {
    mQueue = new MessageQueue();
}

Looper的构造方法同样简单,只是new了一个MessageQueue。 MessageQueue就是一个队列,用链表实现,内部有很多特殊逻辑,本篇不详细分析,在这里只要知道它是一个队列就行了。
到这里,第一句Looper.prepare()已经分析完了,是不是非常简单?再来看第二句mHandler = new Handler()。

public Handler() {
    mLooper = Looper.myLooper();
    mQueue = mLooper.mQueue;
}
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

直接从ThreadLocal里面拿出来之前放进去的Looper,然后把这个Looper和Looper里的MessageQueue都保存在成员变量里,以便后续使用。
现在第二句也分析完了,再看第三句。 Looper.loop();

public static void loop() {
    final MessageQueue queue = sThreadLocal.get().mQueue;
    for (; ; ) {
        Message msg = queue.next(); // might block
        msg.target.dispatchMessage(msg);
    }
}

这个loop方法里有个死循环,不停的从MessageQueue里取next message,然后调用这个message的target的dispatchMessage方法。
这个target又是什么呢?看下面的代码。

public final boolean sendMessage(Message msg) {
    return sendMessageAtTime(msg, 0);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    return enqueueMessage(mQueue, msg, uptimeMillis);
}

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

这是用handler发一个消息的简要流程,调用hanler的sendMessage时,会进过几次调用,调到enqueueMessage方法,里面有一句msg.target = this;可以看出,message的target就是发送这个message的handler,所以上面loop方法里面的 msg.target.dispatchMessage(msg);就是让发送这个message的handler再去调用dispatchMessage方法,这个dispatchMessage方法看名字就知道是处理message的逻辑了。

public void dispatchMessage(Message msg) {
    handleMessage(msg);
}

实际上这个dispatchMessage里面就调到了大家熟悉的handleMessage方法。

到这里,消息是怎么发给handler已经知道了,但是handler是怎么发送消息的呢?继续往下看之前的enqueueMessage方法。

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
        msg.when = when;
        Message p = mMessages;
        Message prev;
        for (; ; ) {
            prev = p;
            p = p.next;
            if (p == null || when < p.when) {
                break;
            }
        }
        msg.next = p;
        prev.next = msg;
        nativeWake(mPtr);
    }
    return true;
}

这里把新加入的消息插入到队列中对应的位置。然后调用nativeWake来通知native层有新消息进来了。

以上,就是整个Handler、Looper、Message的分析,handler往MessageQueue里面发消息,然后looper又一直从MessageQueue里取消息让handler执行,这样就构成了整个消息收发的流程,本文所有代码都是经过简化过的,部分特殊逻辑没有提及,仅供大家初步了解。

上一篇:设计模式(3)---装饰者模式 下一篇:《图解HTTP[上野宣]》读书笔记六-6