Handler源码解析 上

前言

在 Android 编程当中,一般是不可以在子线程中更新主线程的 UI ,这时候 Android 给我们提供了一套在子线程中更新 UI 的消息机制,即 Handler 消息处理机制。

Handler 允许你发送进程消息和可运行的对象到关联的线程消息队列中。每个 Handler 的实例关联一个线程和这个线程的消息队列。当创建一个 Handler 的时候,系统会自动把这个 Handler 实例绑定到当前创建这个 Handler 的线程中。

Handler的基本使用(示例)

[1.0] 在主线程中创建一个 Handler 的实例,并重写 Handler 的 handleMessage(Message msg) 方法

final Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        textView.setText((String)msg.obj);
    }
};

[2.0] 在主线程中创建一个子线程,并通过 Handler 的实例调用 sendMessage 给主线程发送消息

new Thread(new Runnable() {
    @Override
    public void run() {
        Message message = new Message();
        message.obj = "aaa";
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        handler.sendMessage(message);
    }
}).start();

上面代码功能是实现一个启动应用程序 3 秒钟或更新 TextView 控件的内容。下面进行 Handler 的源码分析,Handler 是如何实现上面的逻辑的:也就是 Handler 通过 sendMessage(message) 把一个 Message 实例如何发送给对应的 Handler 的 handleMessage(Message msg) 的:

示例源码分析

下面先从 Message 的入口,也就是 sendMessage(Message msg) 方法开始分析。通过查看 sedMessage(Message msg) 的方法源码,可知道最后会调用到 sendMessageAtTime(Message msg, long uptimeMillis) 方法:

1
2
3
4
5
6
[源码 1]
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue; // 1
...
return enqueueMessage(queue, msg, uptimeMillis);
}

上面的 [源码 1],最重要的需要明白注释 1 处的 mQueue 是来自哪里的消息队列 MessageQueue ,也就是在 Handler 的类中,它是如何初始化拿到实例的。因为在上面的示例源码中的 Handler 实例重写的 handleMessage(Message msg) 是被 dispatchMessage(Message msg) 中调用的,如下面的 [源码 2] 的注释 1 处:

1
2
3
4
5
6
7
8
9
10
11
12
13
[源码 2]
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); // 1
}
}

上面的 dispatchMessage(Message msg) 方法的主要的作用是处理系统的消息的,也可以看作分发系统的消息。好的,我们的重点不在这里,那么是谁调用了 dispatchMessage(Message msg) 这个方法呢?通过查看源码我们会发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[源码 3]
public static void loop() {
final Looper me = myLooper(); // 2
...
final MessageQueue queue = me.mQueue;
...
for (;;) { // 3
Message msg = queue.next();
...
Printer logging = me.mLogging;
...
msg.target.dispatchMessage(msg); // 1
...

// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}

msg.recycleUnchecked();
}
}

在上面的 [源码 3] 中的注释 1 处调用了 dispatchMessage(Message msg) 方法。在注释 2 处,通过调用 myLooper() 获取当前线程的 Looper 对象,而该 Looper 对象携带着当前线程的消息队列(注意:是当前创建 Handler 的线程),而在注释 3 处,for死循环主要的作用是把 queue 这个消息队列里面的 Message 消息取出,然后通过 msg.target.dispatchMessage(msg) 把消息分发出去,也就是调用了 [源码 2] 的 dispatchMessage(msg) 方法。阅读到这里的你,可能心里面有个咕嘟:为什么通过上面 [源码 3] 的注释 2 处调用的 myLooper() 方法就可以获取到当前线程的消息队列呢?
好的,在 Android 系统源码里面最精彩的部分:在 Handler 的构造函数里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[源码 4]
public Handler() {
this(null, false);
}

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());
}
}

mLooper = Looper.myLooper(); // 1
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 3 当前线程的 Looper 对象所持有的消息队列 (mLooper.mQueue 为 final 类型)
mCallback = callback;
mAsynchronous = async;
}

在上面的 [源码 4]中的注释 1 处,可以看到,也是同样地获取当前线程的 Looper 实例 mLooper,然后在注释 3 处,把 final 类型的消息队列实例赋给 mQueue 这个全局变量。到了这里,在 Handler 的构造函数里面初始化了消息队列 MessageQueue,因此,在 [源码 1] 中的 mQueue 便是当前线程 Looper 对象所持有的消息队列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[源码 1]
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue; // 1
...
//queue 消息队列
//msg 需要传递发送的 message
//uptimeMillis 当前消息发送的时间
return enqueueMessage(queue, msg, uptimeMillis);
}

...

[源码 5]
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //把当前的 Handler 的实例赋给 target(private Handler target)
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); // 把消息送进消息队列
}

到了这里,[源码 1] 里面调用的 enqueueMessage(queue, msg, uptimeMillis) 方法,其逻辑如上面的 [源码 5],把需要发送的 Message 发送给了 Looper.myLooper().mQueue 这个消息队列(MessageQueue 是利用类似于单链表的方式, 以 Message 为节点来存储 msg 的,即以链表的方式构造队列);

阅读到这里,你可能会比较疑惑,为什么可以直接通过 Looper.myLooper() 方法获取到 Looper 的实例呢? 其实,Android 应用程序的 Activity 实例是由 ActivityThread 创建的,同时,ActivityThread 也会默认去创建主线程,也会创建主线程的 Looper 的实例。

小结

对上面源码的总结,主要就是: Handler 负责把子线程中传进来的消息(Message),传递给 Looper,由 Looper 把消息封装成消息队列,然后再有 Handler 从消息队列中把消息分发到子线程外面。

本文标题:Handler源码解析 上

文章作者:

发布时间:2018年04月05日 - 22:04

最后更新:2021年06月20日 - 19:06

原始链接:https://hndroid.github.io/2018/04/05/Handler%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-%E4%B8%8A/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。