Android Message Looper 的概念与原理学习

54 阅读5分钟

在学习 Android 消息机制时,总会遇到这些名词:Looper、Handler、MessageQueue。虽然在开发中经常使用它们,比如用 Handler 切线程、延迟任务、更新 UI,但也常常会有一些疑惑:

  • Looper 到底是什么?为什么主线程一定要有它?
  • 消息队列是如何工作的?
  • 这些机制背后到底是怎么实现的?

仅仅停留在“用得会”远远不够,要想真正掌握 Android 的线程模型,就必须深入理解 Looper 的概念与原理。 因此,本篇从基础概念入手,先弄清楚消息机制的作用和结构设计初衷,再通过源码追踪分析其运行流程。

什么是“消息队列”?为什么主线程需要它?

消息队列的概念

消息队列(MessageQueue) 是一个线程内部的任务缓冲区,按时间顺序存储将要被执行的“消息”(Message),等待轮询机制取出并处理。

每个消息代表一个待执行的任务,如:

  • 按钮点击事件
  • View 重绘请求
  • Handler 发出的消息
  • 系统广播、生命周期回调等

这些消息是异步提交的,而消息队列保证它们按序被处理

为什么主线程需要消息队列?

Android 的主线程(也叫 UI 线程)承担着用户交互和界面更新的重任,因此有几个硬性要求:

  • 主线程必须保持“活跃” :不能执行完任务就退出。
  • 主线程不能阻塞:一旦卡顿,界面无法响应,导致 ANR。
  • 事件处理要有顺序:例如点击按钮后应该先处理点击事件,再刷新 UI。
  • 不能抢占执行:任务之间不能互相打断,需按顺序调度。

🧠 这正是“消息队列 + Looper”派上用场的地方

  • 消息队列缓存所有任务;
  • Looper 轮询消息队列,一次只处理一个消息,确保线程安全;
  • Handler 提供接口,支持跨线程提交消息,解耦业务逻辑和线程控制。

所以,主线程需要一个消息驱动机制来:

  • 驱动应用正常运转;
  • 排队管理事件;
  • 保持线程活跃但不高占用;
  • 实现线程间安全通信。

类比解释:主线程像一个“消息处理员”

想象主线程是一个前台接待员:

  • 客人(消息)排队进入前台(消息队列)
  • 前台有个循环机制(Looper),一个个接待
  • 客人有不同需求(消息类型)
  • 每个需求都交给对应的处理者(Handler)

你不能让这个接待员一次同时接待 10 个人,也不能让他下班就不干了,所以:

  • 要有队列(顺序性)
  • 要有调度(轮询)
  • 要有流程控制(派发处理)

原理理解

整体流程图

graph TD
    subgraph "主线程 Thread"
        A[Looper] --> B[MessageQueue]
        D[Handler] --> B
        B --> D
        D --> E[handleMessage]
    end

    subgraph "应用层调用"
        F[sendMessage] --> D
    end

    subgraph "消息循环"
        G[Looper.loop] --> B
        B -->|next取出Message| H[Message]
        H -->|msg.target.dispatchMessage| D
    end
  • Looper:管理消息循环。
  • MessageQueue:消息队列,保存所有待处理的消息。
  • Message:封装具体任务和数据。
  • Handler:用于发送和处理消息。

主线程的 Looper 初始化过程

ActivityThread源码

public static void main(String[] args) {
    ...
    Looper.prepareMainLooper(); // 创建主线程 Looper
    ...
    Looper.loop();              // 开启主线程消息循环
}

Looper.prepareMainLooper()

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

最终调用 prepare() 创建 Looper 并绑定到当前线程:

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

每个线程只能有一个 Looper,存储在ThreadLocal<Looper>中。

Looper.loop() 源码解析

public static void loop() {
    ...
    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);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
           ...
        } finally {
           ...
        }
        msg.recycleUnchecked();
        return true;

}
  • queue.next() 会阻塞直到有消息可处理。
  • msg.target 是 Handler 实例,通过 dispatchMessage() 回调开发者的 handleMessage()
  • 消息处理完成后回收 Message。

MessageQueue 原理

消息入队(enqueueMessage)

Handler.sendMessage() -> Handler.sendMessageDelayed() -> Handler.sendMessageAtTime() -> MessageQueue.enqueueMessage()

java
boolean enqueueMessage(Message msg, long when) {
    ...
    msg.markInUse();
    msg.when = when;
    Message p = mMessages;
    boolean needWake;
    if (p == null || when == 0 || when < p.when) {
        // New head, wake up the event queue if blocked.
        msg.next = p;
        mMessages = msg;
        needWake = mBlocked;
    } else {
        // Inserted within the middle of the queue.  Usually we don't have to wake
        // up the event queue unless there is a barrier at the head of the queue
        // and the message is the earliest asynchronous message in the queue.
        needWake = mBlocked && p.target == null && msg.isAsynchronous();
        Message prev;
        for (;;) {
            prev = p;
            p = p.next;
            if (p == null || when < p.when) {
                break;
            }
            if (needWake && p.isAsynchronous()) {
                needWake = false;
            }
        }
        msg.next = p; // invariant: p == prev.next
        prev.next = msg;
    }
    ...
    return true;
}

插入链表,按时间顺序排序

消息出队(next)

Message next() {
    for (;;) {
        ...
        Message msg = mMessages;
        if (msg != null && msg.when <= now) {
            // 时间到了,取出处理
            mMessages = msg.next;
            return msg;
        }

        // 阻塞等待(使用 native 层 epoll 等)
        nativePollOnce(ptr, nextPollTimeoutMillis);
    }
}

Handler:连接消息与业务逻辑

Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 处理消息
    }
};

handler.sendMessage(Message.obtain(...));

核心方法 dispatchMessage

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

如果 Message 携带了 Runnable,则直接执行;否则走 handleMessage()。

常见问题

为什么在线程里,直接创建 Handler 会崩溃?

因为线程默认没有 Looper,而 Handler 创建时需要绑定一个 Looper,否则会抛出异常:

public Handler() {
    this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
    ...
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
}

在线程中正确使用 Handler 的两种方式

方向一:手动指定 Looper(通常是主线程的 Looper)
适用于:子线程中想向主线程发送消息

Handler mainHandler = new Handler(Looper.getMainLooper());

方向二:在子线程中创建 Looper 和 Handler
适用于:希望子线程拥有自己的消息循环能力(即:让子线程变成一个“消息处理线程”)

new Thread(() -> {
    Looper.prepare();  // 为该线程创建 Looper 和 MessageQueue

    Handler threadHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.d("ThreadHandler", "线程内处理消息: " + msg.what);
        }
    };

    threadHandler.sendEmptyMessage(1);  // 发消息给自己处理(也可以外部调用)

    Looper.loop();  // 启动消息循环
}).start();

或者使用系统封装的 HandlerThread(推荐方式),内部自动创建和管理Looper:

HandlerThread handlerThread = new HandlerThread("WorkerThread");
handlerThread.start();

Handler threadHandler = new Handler(handlerThread.getLooper());
threadHandler.post(() -> {
    Log.d("HandlerThread", "执行异步任务");
});