目录
  1. 1. 一、Java 层四件套
    1. 1.1. 1.1 整体架构
    2. 1.2. 1.2 ActivityThread 中的主线程 Looper
    3. 1.3. 1.3 Looper 与线程绑定
    4. 1.4. 1.4 MessageQueue.enqueueMessage——消息入队
    5. 1.5. 1.5 MessageQueue.next——消息出队与阻塞
  2. 2. 二、Native 层深入
    1. 2.1. 2.1 Java 层与 Native 层的桥梁
    2. 2.2. 2.2 NativeMessageQueue 与 Native Looper
    3. 2.3. 2.3 nativePollOnce——epoll 事件循环核心
    4. 2.4. 2.4 Native Looper::pollOnce——epoll_wait
    5. 2.5. 2.5 eventfd——高效的唤醒机制
  3. 3. 三、同步屏障机制
  4. 4. 四、IdleHandler 机制
  5. 5. 五、Handler 内存泄漏的源码级分析
  6. 6. 六、核心面试题
【吃透源码系列】之Handle

Handler 是 Android 消息驱动模型的核心,也是应用层和系统层之间最关键的线程通信机制。从架构上讲,Handler 涉及 Java 层的 Handler/Looper/MessageQueue/Message 四件套,以及 native 层的 NativeMessageQueue、Looper(native 版)和 epoll 事件循环。本文深入这两层,全面剖析 Handler 的底层运作。

一、Java 层四件套

1.1 整体架构

Handler (发送者 & 处理器)
├── sendMessage(Message) / post(Runnable)
│ └── MessageQueue.enqueueMessage(msg, when)
│ └── 按 when 排序插入单向链表

└── dispatchMessage(Message)
├── msg.callback (Runnable) 优先
├── mCallback.handleMessage 其次
└── handleMessage 最后

MessageQueue (消息队列)
├── enqueueMessage: 插入消息(按 when 有序)
├── next(): 取消息,无消息时阻塞
└── mIdleHandlers: 空闲时执行

Looper (轮询器)
├── prepare(): 创建 Looper + MessageQueue,绑定线程
└── loop(): 死循环调 MessageQueue.next()

AOSP 核心路径:

  • frameworks/base/core/java/android/os/Handler.java
  • frameworks/base/core/java/android/os/Looper.java
  • frameworks/base/core/java/android/os/MessageQueue.java
  • frameworks/base/core/java/android/os/Message.java

1.2 ActivityThread 中的主线程 Looper

// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Looper.prepareMainLooper(); // 创建主线程 Looper

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

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); // 主线程 Handler
}

Looper.loop(); // ← 永不退出的循环!
throw new RuntimeException("Main thread loop unexpectedly exited");
}

这里有个关键认知:为什么死循环不卡死 UI 线程?因为消息循环等价于事件驱动模型。UI 线程在没有消息时处于休眠状态(epoll_wait 阻塞),收到消息才被唤醒。所有 UI 操作(触摸事件、刷新、invalidate)都是通过 Handler 发消息来驱动的,这正是 Android 的事件驱动架构。

1.3 Looper 与线程绑定

// frameworks/base/core/java/android/os/Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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));
}

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); // 创建时即创建 MessageQueue
mThread = Thread.currentThread(); // 绑定当前线程
}

ThreadLocal 的原理是每个线程维护一个独立的 Map(key = ThreadLocal 实例,value = Looper)。因此不同线程的 sThreadLocal.get() 返回的是各自的 Looper。

1.4 MessageQueue.enqueueMessage——消息入队

// frameworks/base/core/java/android/os/MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}

synchronized (this) {
msg.when = when;
Message p = mMessages; // 链表头
boolean needWake;

// 插入逻辑:按 when 从小到大排序
if (p == null || when == 0 || when < p.when) {
// 插入头部
msg.next = p;
mMessages = msg;
needWake = mBlocked; // 如果队列之前是空的(阻塞状态),需要唤醒
} else {
// 插入中间或尾部
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
}
msg.next = p;
prev.next = msg;
}

// 如果需要唤醒,调用 nativeWake
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

1.5 MessageQueue.next——消息出队与阻塞

// frameworks/base/core/java/android/os/MessageQueue.java
Message next() {
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands(); // 处理待定的 Binder 命令
}

// ☆☆☆ native 层阻塞调用 ☆☆☆
nativePollOnce(mPtr, nextPollTimeoutMillis);

synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;

// 处理同步屏障:跳过同步消息,找异步消息
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}

if (msg != null) {
if (now < msg.when) {
// 消息未到时间:计算下次唤醒的超时时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now,
Integer.MAX_VALUE);
} else {
// 消息就绪:从链表中移除并返回
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg; // 返回给 Looper.loop() 执行
}
} else {
nextPollTimeoutMillis = -1; // 无消息:无限等待
}

// IdleHandler 处理
if (pendingIdleHandlerCount < 0 && ...) {
mPendingIdleHandlers = mIdleHandlers.toArray(...);
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null;
boolean keep = false;
try {
keep = idler.queueIdle(); // 执行 IdleHandler
} catch (Throwable t) { ... }
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
}
}
}

二、Native 层深入

2.1 Java 层与 Native 层的桥梁

Java 层的 MessageQueue 在构造时通过 JNI 创建 native 层的 NativeMessageQueue:

// frameworks/base/core/java/android/os/MessageQueue.java
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit(); // JNI 方法,创建 NativeMessageQueue
}

Native 函数映射:

// frameworks/base/core/jni/android_os_MessageQueue.cpp
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); // 返回指针作为 mPtr
}

2.2 NativeMessageQueue 与 Native Looper

// frameworks/base/core/jni/android_os_MessageQueue.cpp
NativeMessageQueue::NativeMessageQueue() :
mPollObj(NULL), mPollEnv(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread(); // 获取线程绑定的 native Looper
if (mLooper == NULL) {
mLooper = new Looper(false); // 首次创建
Looper::setForThread(mLooper);
}
}

2.3 nativePollOnce——epoll 事件循环核心

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue =
reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
mLooper->pollOnce(timeoutMillis); // 核心调用
mPollObj = NULL;
mPollEnv = NULL;
}

2.4 Native Looper::pollOnce——epoll_wait

这是 Handler 机制最底层的核心:

// system/core/libutils/Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents,
void** outData) {
int result = 0;
for (;;) {
// 处理待定的响应(如没有 callback 的事件)
while (mResponseIndex < mResponses.size()) { ... }

// 核心:调用 pollInner,里面调用 epoll_wait
result = pollInner(timeoutMillis);
}
}

int Looper::pollInner(int timeoutMillis) {
// 调整超时(对齐到下一个即将到期的消息)
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
int messageTimeoutMillis = toMillisecondTimeoutDelay(now,
mNextMessageUptime);
if (messageTimeoutMillis >= 0
&& (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
timeoutMillis = messageTimeoutMillis;
}
}

// ★★★ epoll_wait 阻塞等待 ★★★
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS,
timeoutMillis);

// 处理被唤醒的事件
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd.get()) {
if (epollEvents & EPOLLIN) {
awoken(); // 被 wake() 唤醒
}
} else {
// 其他 fd 事件(如 InputChannel、管道)
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
pushResponse(events, mRequests.valueAt(requestIndex));
}
}
}

// 处理 native 消息回调
while (mMessageEnvelopes.size() != 0) { ... }

return result;
}

2.5 eventfd——高效的唤醒机制

Native Looper 使用 Linux eventfd 作为唤醒机制:

// system/core/libutils/Looper.cpp
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollFd(::epoll_create1(EPOLL_CLOEXEC)),
mEpollRebuildRequired(false),
mNextRequestSeq(0),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {

mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));

// 将 mWakeEventFd 加入 epoll 监听
int result = addFd(mWakeEventFd.get(), 0, EPOLLIN, NULL);
}

void Looper::wake() {
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(
write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
}

当 Java 层有新消息入队需要唤醒 epoll_wait 时,调用链是:nativeWake(mPtr)NativeMessageQueue::wake()Looper::wake()write(eventfd, ...) → epoll_wait 被唤醒。

三、同步屏障机制

同步屏障是 Android UI 渲染优化的关键设计。当 View 系统需要刷新 UI 时,它向 MessageQueue 发送一条 target==null 的消息(屏障消息),然后 post 异步消息(如 ChoreographerFrameDisplayEventReceiver)。在 next() 方法中,遇到 target==null 的消息时,会跳过所有同步消息,只处理异步消息,从而确保 UI 渲染优先于普通消息处理。

// frameworks/base/core/java/android/os/MessageQueue.java
// 发送屏障(系统调用)
int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}

private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;

// 关键:屏障消息的 target 为 null
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) {
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}

// 移除屏障
void removeSyncBarrier(int token) {
synchronized (this) {
Message prev = null;
Message p = mMessages;
// 找到 token 对应的屏障消息并移除
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p != null) {
if (prev != null) {
prev.next = p.next;
} else {
mMessages = p.next;
}
p.recycleUnchecked();
}
}
}

四、IdleHandler 机制

IdleHandler 是主线程空闲回调机制,常用于性能优化场景:

// 典型用法:延迟初始化
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// 在 UI 线程空闲时执行非紧急初始化
initNonCriticalComponents();
return false; // 返回 false 表示执行一次后移除
}
});

五、Handler 内存泄漏的源码级分析

泄漏的根本原因在于 Message 持有 Handler 的引用。当一条延迟消息在 MessageQueue 中等待时,其引用链是:

MessageQueue.mMessages → Message → Message.target → Handler → Activity (隐式引用)

如果 Activity 在消息到达前被销毁,但消息还未被处理,Activity 就无法被 GC。

// Handler.enqueueMessage 中设置了 target
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this; // ← 这就是泄漏的根源
return queue.enqueueMessage(msg, uptimeMillis);
}

正确的写法:静态内部类 + WeakReference

static class MyHandler extends Handler {
private final WeakReference<Activity> mActivityRef;

MyHandler(Activity activity) {
mActivityRef = new WeakReference<>(activity);
}

@Override
public void handleMessage(Message msg) {
Activity activity = mActivityRef.get();
if (activity == null || activity.isFinishing()) return;
// 处理消息
}
}

六、核心面试题

Q1:Looper.loop() 是一个死循环,为什么主线程不会卡死?Android 的事件驱动模型和传统阻塞 I/O 模型有什么本质区别?

Looper.loop() 的死循环本质是事件驱动的核心。没有消息时,MessageQueue.next() 通过 native 层的 epoll_wait 进入内核态休眠,CPU 时间片被释放给其他线程。当新消息到达(通过 eventfd 写入唤醒)或 input 事件到达(通过 InputChannel 唤醒)时,epoll_wait 返回,loop 继续处理。这并非忙等(busy-wait),而是一个高效的事件驱动系统。

Q2:Message 的 target 为什么要设计为 Handler 类型?为什么不让 Looper 直接分发到 handlerMessage?

设计为 target 而非 Looper 直接分发有多个好处:(1) 解耦——同一个线程可以有多个 Handler,不同的 Handler 处理不同类型的消息;(2) post(Runnable) 机制——通过 msg.callback 实现 Runnable 的 post,而不需要子类化 Handler;(3) 同步屏障——通过 target==null 可以控制消息优先级(比如 UI 渲染的异步消息优先于同步消息)。

Q3:nativePollOnce 底层用了 epoll,那除了 Handler 的消息唤醒,它还监听哪些 fd 事件?

Native Looper 的 epoll 监听了多个 fd:InputChannel 的 fd(用于接收 InputDispatcher 发送的输入事件)、eventfd(Java 层消息插入时的唤醒)、以及由 addFd() 注册的其他 fd(如某些 Native 组件的通信管道)。这也就是为什么 Looper 不仅能处理 Handler 消息,还能响应触摸/按键事件。

AOSP 核心路径参考:

  • frameworks/base/core/java/android/os/Handler.java
  • frameworks/base/core/java/android/os/Looper.java
  • frameworks/base/core/java/android/os/MessageQueue.java
  • frameworks/base/core/java/android/os/Message.java
  • frameworks/base/core/jni/android_os_MessageQueue.cpp
  • system/core/libutils/Looper.cpp
  • system/core/libutils/include/utils/Looper.h
打赏
  • 微信
  • 支付宝

评论