深入理解Android消息机制(二)Handler工作过程

本系列相关阅读

  • 深入理解Android消息机制(一)初识
  • 深入理解Android消息机制(二)Handler工作过程
  • 深入理解Android消息机制(三)原理分析

前篇回顾

  • Android的消息机制主要是指Handler运行机制
    由于Android开发规范明确表示只能在主线程更新UI,因此当子线程完成工作,我们需要使用Handler切换到主线程执行UI更新操作。
  • MessageQueue 消息队列
    用来缓存一系列待处理的消息,它的内部存储结构并不是真正的队列,而是采用单链表结构来存储消息列表。
  • Looper 循环
    MessageQueue不能处理消息,这个工作由Looper来完成。它是以无限循环的形式去检查消息队列中是否有新消息,如果有的话就处理消息,如果没有就一直等待。
  • ThreadLocal
    一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。Handler中主要用它来存储当前线程的Looper对象

上一篇已经介绍了Handler的简单使用,本文简单描述一下Handler的工作过程。

Handler创建完成之后,内部的MessageQueue和Looper就会和Handler一起协同工作。Handler拥有一系列post/send方法,通过源码我们可以发现,post方法最终还是通过send方法来完成的,我们接下来从源码角度分析Handler的工作流程:

1. Handler把消息放入消息队列

Handler开始工作的第一步就是调用send系列方法,最终调用的是sendMessageAtTime方法,查看源码:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

这段代码比较简单,sendMessageAtTime方法内部会调用MessageQueue的enqueueMessage方法,将消息放入到消息队列中去。有一个小细节需要注意,消息放入到消息队列之前,会先将这个消息与发送它的Handler进行绑定,也就是使用一个变量 msg.target来存储当前Handler的引用,在接下来的消息处理中会用到它。

2. Looper从消息队列中取出消息并交给Handler处理

通过上一篇文章我们知道,Looper的主要工作就是不停地检查消息队列中是否有新消息:如果消息队列中有新消息,取出消息并交给Handler处理;如果没有消息就一直阻塞在那里。我们很容易就可以猜到这些任务都是在Looper.loop()方法中完成的,为了验证我们的猜想,接下来我们看看loop方法:

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {  //判断在这之前是否执行过Looper.prepare() 
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    ……
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // 没有消息说明消息队列正在退出
            return;
        }
        try {
            msg.target.dispatchMessage(msg); //把消息交给Handler处理
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        msg.recycleUnchecked();
    }
}

上面是loop方法的核心代码,主要步骤如下

  • 首先通过ThreadLocal获取当前线程的Looper:如果Looper为null,说明当前线程还没有执行过Looper.prepare()方法,抛出异常提示用户当前线程没有Looper;Looper不为空就继续向下执行。
  • 使用无限for循环检查消息队列中是否有新消息:如果没有新消息则表明消息队列正在退出,整个消息循环也就结束了;如果有新消息,调用Handler的dispatchMessage方法,把消息传递给Handler去处理。需要注意的是,处理消息的Handler必须是把消息放入消息队列中的那个Handler,由于在enqueueMessage方法中我们使用msg.target存储了当前Handler的引用,所以直接使用msg.target来处理消息即可。

3. Handler对消息进行处理

Handler的dispatchMessage方法主要负责处理Looper发送过来的消息:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {   //消息是用post系列方法加入到消息队列中的
        handleCallback(msg);
    } else {//消息是用send系列方法加入到消息队列中的
        if (mCallback != null) {    //用接口作为参数创建Handler对象
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); //继承Handler类的时候,通常都要重写这个方法
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}

dispatchMessage方法内部逻辑在代码中已经注释,具体流程见下图。


消息处理流程图

下一篇:深入理解Android消息机制(三)原理分析


参考

《Android开发艺术探索》

你可能感兴趣的:(深入理解Android消息机制(二)Handler工作过程)