欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android消息机制三剑客之Handler、Looper、Message源码分析(一)

程序员文章站 2022-07-14 19:53:55
...

Android消息机制:
Android消息机制三剑客之Handler、Looper、Message源码分析(一)
Android消息机制三剑客之Handler、Looper、Message源码分析(二)

1、What is Handler?

    对与Handler的解释没有什么比源码中给的注释再准确的了,下面会依据这些注释进行简单的翻译并结合上自己的理解进行描述一下,通过这些对Handler类已经可以了解的差不多了:

/**
 * A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread's {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread's message
 * queue.  When you create a new Handler, it is bound to the thread /
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
 * 
 * <p>There are two main uses for a Handler: (1) to schedule messages and
 * runnables to be executed as some point in the future; and (2) to enqueue
 * an action to be performed on a different thread than your own.
 * 
 * <p>Scheduling messages is accomplished with the
 * {@link #post}, {@link #postAtTime(Runnable, long)},
 * {@link #postDelayed}, {@link #sendEmptyMessage},
 * {@link #sendMessage}, {@link #sendMessageAtTime}, and
 * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow
 * you to enqueue Runnable objects to be called by the message queue when
 * they are received; the <em>sendMessage</em> versions allow you to enqueue
 * a {@link Message} object containing a bundle of data that will be
 * processed by the Handler's {@link #handleMessage} method (requiring that
 * you implement a subclass of Handler).
 * 
 * <p>When posting or sending to a Handler, you can either
 * allow the item to be processed as soon as the message queue is ready
 * to do so, or specify a delay before it gets processed or absolute time for
 * it to be processed.  The latter two allow you to implement timeouts,
 * ticks, and other timing-based behavior.
 * 
 * <p>When a
 * process is created for your application, its main thread is dedicated to
 * running a message queue that takes care of managing the top-level
 * application objects (activities, broadcast receivers, etc) and any windows
 * they create.  You can create your own threads, and communicate back with
 * the main application thread through a Handler.  This is done by calling
 * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
 * your new thread.  The given Runnable or Message will then be scheduled
 * in the Handler's message queue and processed when appropriate.
 */

    Hanlder,你可以使用它发送或处理与当前线程的MessageQueue关联的Message或Runnable对象(这里使用Message时一般用于消息传递,使用Runnable时一般用于线程操作,后续会介绍)。每个Handler实例都会与一个单一的线程和该线程的消息队列关联。(面试题:那么这种关联是什么时候建立的呢?)每当你创建一个Handler实例时,它会与创建它的线程及该线程的消息队列进行绑定,在需要的时候,Handler就将message和runnable插入消息队列中,随着从队列中取出而执行。
    Handler主要由两种用途:(1)对message和runnable的执行进行调度;
(2)在其他线程中执行某个操作(B线程可以调用A线程的Handler从而在A线程中执行操作)。
    调度message有以下几种方法,功能根据字面含义就可知道,详细实现还请查看源码:
- post;
- postAtTime(Runnable,long);
- postDelayed;
- sendEmptyMessage;
- sendMessage;
- sendMessageAtTime;
- sendMessageDelayed;
    post系列的方法用于入队Runnable对象供message queue调用,Runnable对象即发布一个可执行任务,该任务仍然在本线程中运行,如果将该对象去实现一个Thread,那么就会运行在新建立的Thread中;sendMessage系列的方法用于入队Message对象,并且可以使用bundle携带信息用于传递,同时需要在自定义Handler子类中重写handleMessage方法,用于接受和处理收到的Message对象。而上述带AiTime或Delayed后缀的方法可以在指定时间或延后一定时间后再去执行(对应上述第(1)种用途)。
    当应用的进程被创建后,主线程(此处进程与线程的区别)中会维护一个消息队列用于管理高级别的应用对象(例如Activities、broadcast receivers 等等)和它们创建的一系列Window。我们可以通过Handler进行主线程和自创建线程之间的通信。也就是在子线程中调用主线程的Handler通过上述的post、send系列方法进行通信。发送的Message或Runnable对象会入队到主线程的消息队列,并在出队时执行(对应上述第(2)种用途)。
    虽然Handler中定义了这么多方法,但其实内部最终调用的都是sendMessageAtTime(Message msg, long uptimeMillis) 方法:

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

    在该方法中,引入了MessageQueue,并且先是调用了本地方法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);
    }

    在Handler类中定义的enqueueMessage方法中,首先为Message对象设置了target,即将当前Handler与Message对象绑定,然后调用了MessageQueue中的enqueueMessage方法,该方法我们在后面分析。

2、what is Looper

    同样,我们从Looper.class源码中给定的注释先来弄清楚什么是Looper。

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  * 
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  * 
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */

    该类为一个线程运行一个消息环。通常默认的一个线程是不带有与之关联的消息环,Looper中可以调用prepare方法在线程中运行起一个消息循环,然后调用loop()方法使其开始处理Message直至消息循环停止。Lopper通常都是和Handler共同使用的。
    然后官方提供了一个典型Thread、Looper、Handler的实现示例,该示例中,使用prepare和loop分离来创建一个使用Looper来通信的Hanlder。
    官方注释中很明确提到了Looper最为关键的两个方法,Looper.prepare()为线程准备好Looper,进行初始化的操作,Looper.loop()为线程开启消息处理。那么后续我们着重分析一下这两个方法。

3、what is MessageQueue

    MessageQueue在官方注释中是最少的一个,理解起来也很简单,就是存放message对象的一个单向链表的队列,使用Handler进行入队操作,在Lopper中通过myQueue()方法获取当前线程绑定的MessageQueuue,并进行出队和消息分发。

/**
 * Low-level class holding the list of messages to be dispatched by a
 * {@link Looper}.  Messages are not added directly to a MessageQueue,
 * but rather through {@link Handler} objects associated with the Looper.
 * 
 * <p>You can retrieve the MessageQueue for the current thread with
 * {@link Looper#myQueue() Looper.myQueue()}.
 */

4、总结

    通过对三个类官方注释的分析,我们可以了解Handler用来发送、接收并处理消息,是消息通信的起点与终点;MessageQueue则以队列的形式存放由Handler发送来的Message对象;而Looper通过prepare()初始化线程的通信环境,通过loop()开启循环,从MessageQueue中取出消息并分发给对应的Hanlder。那么这三者是如何协同工作,完成消息通信的呢,请看下一篇消息机制的原理分析。