消息机制

Android 的消息机制基于 ​​Handler、Looper、MessageQueue​​ 实现,用于同一进程内的线程间通信。其核心目的是将任务切换到指定线程执行(如子线程更新 UI)。下面是一个简单的入门案例:

// 主线程创建 Handler(关联主线程 Looper)
val handler = object : Handler(Looper.getMainLooper()) {
    override fun handleMessage(msg: Message) {
        // 处理消息(例如更新 UI)
        if (msg.what == 1) {
            Log.d("my_tag", "${Thread.currentThread().name}, $msg")
        }
    }
}

Thread {
    // 子线程发送消息到主线程
    val message = Message.obtain()
    message.what = 1
    handler.sendMessage(message)
}.start()

Android 消息机制中的三个核心组件如下:

  • Handler:消息的发送者和接收者;

  • Looper:消息循环器,负责从消息队列中取出消息,并分发给对应的 Handler;

  • MessageQueue:消息队列,用于存储待处理的消息。

Looper 消息循环器

每个线程可以通过 Looper.prepare() 来初始化自己的消息循环器。主线程在应用启动时就已经创建好了 Looper:

public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal {
    public static void main(String[] args) {
        // ...
        Looper.prepareMainLooper(); // 为主线程准备消息循环
        // ...
        Looper.loop(); // 主线程开始处理消息(进入死循环)
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}

Looper 的创建通过 ThreadLocal 实现,保证每个线程只存在一个 Looper 实例,每个 Looper 内部持有一个唯一的 MessageQueue,用于处理该线程内所有的消息。

public final class 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();
        }
    }

    private static void prepare(boolean quitAllowed) {
        // 通过 ThreadLocal 确保一个线程只能存在一个 Looper
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    // Looper 构造函数,每个 Looper 持有一个唯一的 MessageQueue
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    
    // 获取当前线程中的 Looper
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

Handler 发送消息

Handler 在构造时会绑定指定线程的 Looper(默认是当前线程的 Looper),并持有其内部的 MessageQueue。调用 sendMessage() 方法时,消息被放入该线程的队列中。

public class Handler {    
    // 构造函数
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async, boolean shared) {
        mLooper = looper;
        mQueue = looper.mQueue; // 获取 looper 中的消息队列
        mCallback = callback;
        mAsynchronous = async;
        mIsShared = shared;
    }
    
    // 消息的发送本质是通过 enqueueMessage() 完成的:
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) {
        msg.target = this; // 设置消息的目标为当前 Handler
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}

Looper 分发消息

Looper 创建后还需要开启消息循环,不然不能处理消息。主线程的 Looper 会在程序启动时就开启消息循环,它是一个死循环,会不断从 MessageQueue 中取出消息,并调用 msg.target.dispatchMessage() 进行分发:

public final class Looper {
    public static void loop() {
        final Looper me = myLooper();
        // ....

        for (;;) {  // 无限循环
            // 处理一条消息
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

    private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }
        // ...
        try {
            msg.target.dispatchMessage(msg); // 分发消息
            // ...
        } catch (Exception exception) {
            // ...
        } finally {
            // ...
        }
    }
}

消息在被 Handler 发送时,将 msg.target 属性设置为了自己 this,当 Looper 拿到一条消息后,会调用 msg.target (也就是发送时的 Handler)去处理消息,这样就实现了分发到指定的 Handler。

dispatchMessage() 内部,会调用我们覆写的 handleMessage() 方法:

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

消息机制总结

  • 初始化:线程的 Looper 必须先初始化和开启消息循环,主线程的 Looper 启动时已经创建好;

  • 绑定:Handler 绑定到某个线程的 Looper,间接持有该线程的消息队列;

  • 发送:Handler 发送消息,写入目标线程的消息队列;

  • 分发:Looper 从消息队列中获取消息,调用消息中的 target(即原始发送的 Handler),执行 handleMessage() 处理逻辑。