This page looks best with JavaScript enabled

Android消息机制

 ·  ☕ 2 min read

在非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 原理图

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

1
2
3
4
5
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()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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;
    ...
}
1
2
3
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

Looper.loop()

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

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

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    //进入无限循环
        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()插入到消息队列。

Support the author with
alipay QR Code
wechat QR Code

Yang
WRITTEN BY
Yang
Developer