深入理解Message, MessageQueue, Handler和Looper

做过Android的都知道Message, MessageQueue, Handler和Looper,但知道不代表你理解它们。有时觉得用得很顺手,但Android怎么实现又说不上来,总觉得似懂非懂。不把它们攻破实在浑身不舒服。

先让我们一句话总结,再开始分析。

Looper不断获取MessageQueue中的一个Message,然后交给Hanlder处理。

其实Message和Runnable可以一并压入MessageQueue中,形成一个集合,后面将有所体现。

本文所涉及的代码文件以及路径:

frameworks/base/core/java/android/os/Hanlder.java
frameworks/base/core/java/android/os/Message.java
frameworks/base/core/java/android/os/MessageQueue.java
frameworks/base/core/java/android/os/Looper.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/jni/android_os_MessageQueue.cpp

1、Message

android.os.Message定义了消息必要的描述和属性数据。

深入理解Message, MessageQueue, Handler和Looper

public final class Message implements Parcelable {
    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    public Messenger replyTo;
    Bundle data;
    Handler target;
    Runnable callback;
    ......
}

深入理解Message, MessageQueue, Handler和Looper

请注意里面的target和callback,后面将对此进行关联。其中arg1和arg2是用来存放整型数据的,what用来保存消息标识,obj是Object类型的任意对象,replyTo是消息管理器,会关联到一个handler。通常Message对象不是直接new出来,只要调用handler中的obtainMessage方法来直接获得Message对象。这也是Android推荐的做法。

深入理解Message, MessageQueue, Handler和Looper

/**
 * Return a new Message instance from the global pool. Allows us to
 * avoid allocating new objects in many cases.
 */
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

深入理解Message, MessageQueue, Handler和Looper

你看,如果池中没有才会new一个Message。

2、MessageQueue

MessageQueue是一个final class,用来存放消息的消息队列,它具有队列的常规操作,包括:

  • 新建队列
  • MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }
  • private native static long nativeInit();

    由代码可以看出,由构造函数和本地方法nativeInit()组成。其中,nativeInit()会在本地创建一个NativeMessageQueue对象,然后赋给MessageQueue中的成员变量,这一系列通过内存指针进行。

  • 深入理解Message, MessageQueue, Handler和Looper

    static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
        NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
        if (!nativeMessageQueue) {
            jniThrowRuntimeException(env, "Unable to allocate native queue");
            return 0;
        }
    
        nativeMessageQueue->incStrong(env);
        return reinterpret_cast<jlong>(nativeMessageQueue);
    }

    深入理解Message, MessageQueue, Handler和Looper

  • 元素入队
  • boolean enqueueMessage(Message msg, long when)
  • 元素出队
  • Message next()
  • 元素删除
  • void removeMessages(Handler h, Runnable r, Object object)
    void removeMessages(Handler h, int what, Object object)
  • 销毁队列
  • 深入理解Message, MessageQueue, Handler和Looper

    // Disposes of the underlying message queue.
    // Must only be called on the looper thread or the finalizer.
    private void dispose() {
        if (mPtr != 0) {
            nativeDestroy(mPtr);
            mPtr = 0;
        }
    }

    深入理解Message, MessageQueue, Handler和Looper

    销毁队列也需要用到本地方法,此处就不展开了。

3、Handler

Handler作为消息处理者,一是处理Message,二是将某个Message压入MessageQueue中。Handler类中持有MessageQueue和Looper成员变量(后面再体现它们的作用):

深入理解Message, MessageQueue, Handler和Looper

public class Handler {
    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;
    ......
}

深入理解Message, MessageQueue, Handler和Looper

先让我们focus Handler如何处理Message

public void dispatchMessage(Message msg)
public void handleMessage(Message msg)

一个对Message进行分发,一个对Message进行处理。

还记得开始的一句话总结么?Looper从MessageQueue中取出一个Message后,首先会调用Handler.dispatchMessage进行消息分发。这里虽然还没涉及Looper的讨论,但可以先给出消息分发的代码,具体在Looper类的loop方法中

深入理解Message, MessageQueue, Handler和Looper

public static void loop() {
    ......
    for (;;) {
        ......
        msg.target.dispatchMessage(msg);
        ......
    }
}

深入理解Message, MessageQueue, Handler和Looper

好,回到Handler的dispatchMessage方法

深入理解Message, MessageQueue, Handler和Looper

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

深入理解Message, MessageQueue, Handler和Looper

通过代码得知,默认情况下Handler的派发流程是:

  • 如果Message中的callback不为空,通过callback来处理(开头我们提到Message中有一个callback)
  • 如果Handler的mCallback不为空,通过mCallback来处理
  • 如果上面两个都为空,才调用handleMessage来处理

其中mCallback为

public interface Callback {
    public boolean handleMessage(Message msg);
}

而一般情况下,我们就是通过直接new Handler的方式重写handleMessage来处理Message,这个Handler就是消息处理责任人。

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

接着,Handler第二个作用是将某个Message压入MessageQueue中。大家注意没有,Message是Handler处理,而Message也是Handler压入到MessageQueue中,既然这样,为什么不直接执行?其实这样是体现程序设计的有序性,如果事件优先级较小,就需要排队,否则马上处理。

将Message压入到MessageQueue中,能调用的主要的方法有:

public final boolean post(Runnable r)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)

深入理解Message, MessageQueue, Handler和Looper

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

深入理解Message, MessageQueue, Handler和Looper

post系列的方法会调用相应的sendEmptyMessage、sendEmptyMessageDelayed等方法,最终进入sendMessageAtTime中,然后调用enqueueMessage,把Message压入队列中。

由于post方法的参数是Runnable对象,所以Hander内部提供了getPostMessage方法把Runnable对象转化为Message

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

最终,Handler形成了一个循环:Handler->MessageQueue->Message->Handler

4、Looper

Looper也是一个final class,并且持有一个MessageQueue,MessageQueue作为线程的消息存储仓库,配合Handler, Looper一起完成一系列操作。值得注意的是,还有一个final Thread和一个final ThreadLocal<Looper>的成员变量,其中ThreadLocal负责创建一个只针对当前线程的Looper及其它相关数据对象,其它线程无法访问。

Looper类中的注释还给了一个使用Looper的普通线程范例:

深入理解Message, MessageQueue, Handler和Looper

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

深入理解Message, MessageQueue, Handler和Looper

其实就是三个步骤:

  • Looper.prepare()准备工作
  • 创建消息处理的handler
  • 调用Looper.loop()进入消息循环

看起来简单吧?可是你能看出mHandler是怎样把消息投递到Looper所管理的MessageQueue中的么?Looper在什么时候创建呢?

先看一下Looper.prepare()到底做了什么事情

深入理解Message, MessageQueue, Handler和Looper

public static void prepare() {
    prepare(true);
}

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

深入理解Message, MessageQueue, Handler和Looper

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

首先通过sThreadLocal.get()判断保证一个Thread只能有一个Looper实例,最后new Looper完成Looper的实例化。同时MessageQueue就在Looper的构造函数中创建出来。

再来看handler的创建。还记得前面提到的Handler类中的成员变量么?Handler中就持有一个Looper,这样一来,Handler就和Looper关联起来了。Handler一共有7个构造函数,看其中一个:

深入理解Message, MessageQueue, Handler和Looper

public Handler(Callback callback, boolean async) {
    ......
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

深入理解Message, MessageQueue, Handler和Looper

Looper中的myLooper()

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

这样一来,Handler中的构造函数通过Looper.myLooper()获取当前线程中的Looper实例,实际上就是Looper中的sThreadLocal.get()调用;然后把mLooper.mQueue赋给Handler的mQueue,最终Handler, Looper和MessageQueue就联系起来了。后续Handler执行post/send系列的方法时,会将消息投递给mQueue,也就是mLooper.mQueue中。一旦Looper处理到消息,它又从中调用Handler来进行处理。

最后看Looper.loop()。

它有两个作用,一是创建处理消息的环境;二是循环处理消息。

深入理解Message, MessageQueue, Handler和Looper

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

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

深入理解Message, MessageQueue, Handler和Looper

由前面得知,myLooper()就是调用sThreadLocal.get()来获取与之匹配的Looper实例。me.mQueue验证了每一个Looper中都自带了一个MessageQueue。进入for循环后,开始从MessageQueue中取出一个消息(可能会阻塞),如果当前消息队列中没有Message,线程退出;否则分发消息。msg.target.dispatchMessage(msg)中的target就是一个Handler。最后消息处理完毕,进行回收。

平时我们在Activity中使用Handler处理Message时,为什么看不到Looper呢?这只能说Android偷偷为我们做了一些背后的工作。好了,UI线程要上场了。

5、ActivityThread

没错,ActivityThread就是我们熟悉的UI线程,它在应用程序启动的时候由系统创建出来。先来看一下这个UI线程的main函数

深入理解Message, MessageQueue, Handler和Looper

public static void main(String[] args) {
        ......
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        ......
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

深入理解Message, MessageQueue, Handler和Looper

有两点与普通线程不一样的地方。

普通线程只要prepare就可以了,而主线程使用的是prepareMainLooper;普通线程生成一个与Looper绑定的Handler对象就行,而主线程是从当前线程中获取Handler(thread.getHandler())。

深入理解Message, MessageQueue, Handler和Looper

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

深入理解Message, MessageQueue, Handler和Looper

其实prepareMainLooper也是调用prepare,只是不让该线程退出。经过prepare后,myLooper()就得到一个本地线程<ThreadLocal>的Looper对象,然后赋给sMainLooper,也就是UI线程的Looper。如果其它线程想获得主线程的Looper,只需调用getMainLooper()。

public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}

再来看thread.getHandler()。

其实ActivityThead内部有一个继承Handler的H类

深入理解Message, MessageQueue, Handler和Looper

private class H extends Handler {
    ......
    public void handleMessage(Message msg) {
        ......
    }
    ......
}

深入理解Message, MessageQueue, Handler和Looper

final H mH = new H();

所以thread.getHandler()返回的就是mH,这样ActivityThread也有一个Handler处理各种消息了。

总结一下。

  • 每个Thread只对应一个Looper
  • 每个Looper只对应一个MessageQueue
  • 每个MessageQueue有N个Message
  • 每个Message最多指定一个Handler来处理

而Thread和Handler是一对多的关系。

深入理解Message, MessageQueue, Handler和Looper

到这里,是不是对Message, MessageQueue, Handler和Looper有了更深的认识呢?

 

参考:

《深入理解Android内核设计思想》 林学森 编著