Handler消息处理机制源码解析 上

249 阅读5分钟

前言

在 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]
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 处:

[源码 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) 这个方法呢?通过查看源码我们会发现:

[源码 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 的构造函数里面:

[源码 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]
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 事件处理机制的原理解析就到这里结束了,感谢你的阅读...

原文章地址