Android 消息队列机制

时间:2023-03-10 01:00:51
Android 消息队列机制

在非UI线程使用Handler进行线程通信时,一般都需要进行3个步骤:

  • 创建Looper Looper.prepar()
  • 创建Handler
  • 启动消息循环Looper.loop()

通过这3步,基本就建立好了 Android 的多线程消息通信机制:

  • Handler
  • MessageQueue
  • Looper
  • Message

这几者可谓是你中有我,我中有你的存在。通过 Handler 发送 Message 到 Looper 的 MessageQueue 中,待 Looper 的循环执行到 Message 后,就会根据 Message 的 target handler,回调对应 Handler 的 handlerMessage 方法。

例如: Thread-A 拥有一个 Looper,Thread-B 持有一个在 Thread-A 中构造的 Handler,Thread-B 就可以通过这个 Handler 将 Message 发送到 Thread-A 的 Looper 的 MessageQueue 中,然后消息会走到 Thread-A 的 Handler 的 handleMessage 方法。

Looper 原理图

Android 消息队列机制

在 Looper 类加载时就会创建一个 ThreadLocal 类型的类变量 sThreadLocal

public final class Looper {
private static final String TAG = "Looper"; // sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

Looper.prepar()

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");
}
// 将构造的 looper 存到类变量 sThreadLocal 中
sThreadLocal.set(new Looper(quitAllowed));
} private Looper(boolean quitAllowed) {
// 构建一个 messageQueue 成员
mQueue = new MessageQueue(quitAllowed);
// 将当前线程存入 mThread 中
mThread = Thread.currentThread();
}

在这里面主要执行了 3 步:

  • 构建一个 looper
    • 构建一个 messageQueue 成员
    • 将当前线程存入 mThread 中
  • 将构造的 looper 存到类变量 sThreadLocal 中

至此,执行 Looper.praper 的当前线程就会拥有一个 looper 成员了,存放在 Looper 的 sThreadLocal 中。

创建Handler

public Handler(Callback callback, boolean async) {
...
// 通过`Looper.myLooper()` 类方法获取 sThreadLocal 中储存的当前线程的 looper,将这个 looper 绑定到 handler 的成员变量 mLooper 中
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
// 将 mLooper 中的 messageQueue 绑定到 handler 的成员变量 mQueue 中
mQueue = mLooper.mQueue;
...
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

Looper.loop()

  • 声明一个局部常量final Loop me = myLoop()

    • myLoop()将返回当前线程的looper成员
  • 声明一个局部常量final MessageQueue queue

    • 将me.mQueue赋值给queue
  • 进入无限循环

    //进入无限循环
    for (;;) {
    //取出一条消息
    Message msg = queue.next();
    //没有消息就阻塞
    if (msg == null) {
    return;
    }
    ... //分发消息
    try {
    msg.target.dispatchMessage(msg);
    //msg.target是一个Handler对象
    } finally {
    if (traceTag != 0) {
    Trace.traceEnd(traceTag);
    }
    }
    ... //回收消息
    msg.recycleUnchecked();
  • 通过Message.obtain()获取的消息,需要使用Handler.sendMessage()插入到消息队列。

  • 通过Handler.obtainMessage()获取的消息,可以使用message.sendToTaget()插入到消息队列。