Handler机制的核心价值与设计背景
在Android中,只能在主线程(UI线程)中更新UI,这是为了保证UI操作的线程安全性。
常见的情况是:
- 网络请求、文件读写、数据库操作等耗时任务必须在子线程执行
- 这些任务完成后需要将结果反馈到UI线程更新界面
java
// 错误示例:直接在子线程更新UI
new Thread(() -> {
// 模拟耗时操作
Thread.sleep(2000);
// ❌ 直接更新UI会导致崩溃或不可预知的行为
textView.setText("任务完成");
}).start();
Android采用了消息队列(Message Queue)模型来解决这个问题,而不是简单的线程同步机制(如锁、信号量)。这是因为:
- 解耦生产者和消费者:发送消息的线程不需要知道接收线程的状态
- 支持延迟和定时消息:可以调度未来某个时间点执行的任务
- 有序处理:消息按照先进先出(FIFO)的顺序处理
- 线程安全:消息队列内部实现了线程同步
通俗解释:
kotlin
**传统方式(同步机制)** :没有驿站,直接送货
// 就像:快递员直接上门,你必须在家等着
class TraditionalDelivery {
void deliverPackage() {
synchronized(lock) { // 就像敲门
if (homeHasPerson) { // 你在家吗?
receivePackage(); // 签收
} else {
wait(); // 快递员在门口等着
}
}
}
}
**消息队列方式**:有驿站
// Android的消息队列就像驿站
class MessageQueueExample {
// 发送消息就像把快递放驿站
fun sendMessage(msg: Message) {
messageQueue.enqueueMessage(msg) // 放入驿站
// 放完就走,不用等收件人
}
// 主线程(收件人)有空时去驿站取
fun processMessages() {
while (true) {
val msg = messageQueue.nextMessage() // 去驿站取快递
handleMessage(msg) // 处理/签收
}
}
}
Handler机制由三个紧密协作的类组成:
| 组件 | 角色 | 类比 |
|---|---|---|
| Handler | 消息的发送者与处理者 | 快递员(收件和派件) |
| MessageQueue | 消息的存储队列 | 快递仓库(暂存包裹) |
| Looper | 消息的循环分发器 | 仓库分拣员(不断取件) |
重要原则 :一个线程只能有一个Looper和一个MessageQueue,但可以有多个Handler。
核心组件
MessageQueue:消息队列
MessageQueue是Handler机制的存储核心,它内部维护了一个消息链表。
java
// MessageQueue中的关键结构
public final class MessageQueue {
// 消息队列的头部,链表结构
private Message mMessages;
// 标记是否需要退出循环
private boolean mQuitting;
// 用于线程同步的锁
private final Object mLock = new Object();
// 空闲处理器集合
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<>();
}
消息入队:当Handler发送消息时,最终会调用MessageQueue的enqueueMessage方法:
java
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 情况1:队列为空,或新消息的执行时间最早
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // 如果当前阻塞,需要唤醒
}
// 情况2:插入到链表中间合适位置
else {
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;
prev.next = msg;
}
// 如果需要唤醒,则调用nativeWake
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
- 消息按执行时间(when)排序:不是简单的先进先出,而是按执行时间排序
- 线程安全 :通过
synchronized保证多线程安全 - 唤醒机制:如果队列为空时Looper正在阻塞,插入新消息需要唤醒它
消息出队:Looper通过消息队列提供的next()方法从队列中获取消息:
java
Message next() {
for (;;) {
// 1. 处理空闲处理器(IdleHandler)
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有空闲处理器,进入阻塞
mBlocked = true;
continue;
}
// 2. 从队列头部取消息
synchronized (this) {
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;
return msg;
}
} else {
// 队列为空,无限等待
nextPollTimeoutMillis = -1;
}
}
// 3. 没有消息,进入阻塞状态(Native层实现)
nativePollOnce(ptr, nextPollTimeoutMillis);
}
}
- 阻塞优化:没有消息时,Looper会在Native层阻塞,不消耗CPU
- 时间调度:消息按执行时间排序,未到时间的消息会等待
- 空闲处理:在等待消息时,会执行IdleHandler
Looper:消息循环的引擎
Looper是让线程拥有消息循环能力的关键组件。
Looper初始化:
java
// 主线程的Looper在ActivityThread.main()中初始化
public static void main(String[] args) {
// 1. 准备主线程Looper
Looper.prepareMainLooper();
// 2. 创建ActivityThread实例
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 3. 开始消息循环
Looper.loop();
// 4. 正常情况下不会执行到这里
throw new RuntimeException("Main thread loop unexpectedly exited");
}
普通线程创建Looper:
java
class WorkerThread extends Thread {
public Handler handler;
@Override
public void run() {
// 1. 准备Looper(创建Looper和MessageQueue)
Looper.prepare();
// 2. 创建Handler,会自动绑定当前线程的Looper
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
// 3. 开始消息循环
Looper.loop();
}
// 4. 安全退出循环
public void quit() {
if (handler != null) {
handler.getLooper().quit();
}
}
}
每个线程只能有一个Looper,这是通过ThreadLocal实现的:
java
public final class Looper {
// ThreadLocal存储每个线程的Looper实例
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
// 准备Looper
private static void prepare() {
// 检查是否已经准备过
if (sThreadLocal.get() != null) {
throw new RuntimeException("一个线程只能创建一个Looper");
}
// 创建Looper并存入ThreadLocal
sThreadLocal.set(new Looper());
}
// 获取当前线程的Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
}
- 每个Thread对象内部有一个
ThreadLocalMap ThreadLocal作为key,Looper作为value存储- 这样每个线程都能独立访问自己的Looper,互不干扰
Looper.loop()是Handler机制的心脏:
java
public static void loop() {
// 1. 获取当前线程的Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 2. 获取消息队列
final MessageQueue queue = me.mQueue;
// 3. 开始无限循环
for (;;) {
// 4. 获取下一条消息(可能会阻塞)
Message msg = queue.next();
if (msg == null) {
// 没有消息,退出循环
return;
}
// 5. 分发消息给Handler处理
try {
msg.target.dispatchMessage(msg);
} finally {
// 确保消息回收
msg.recycleUnchecked();
}
}
}
为什么loop()不会导致ANR?
- ANR是因为主线程的
Looper.loop()在某次消息处理时耗时过长 - 不是
loop()本身导致的,而是handleMessage()中的代码太耗时 queue.next()在没有消息时会阻塞,不消耗CPU
loop()如何退出?
- 调用
Looper.quit()或Looper.quitSafely() quit()立即退出,丢弃所有未处理消息quitSafely()处理完所有非延迟消息后退出
Handler:消息的生产者与消费者
Handler是开发者最直接接触的组件,它既是消息的发送者 ,也是处理者。
Handler必须与一个Looper关联,有几种构造方式:
java
// 方式1:默认关联当前线程的Looper
// 如果当前线程没有Looper会崩溃
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
// 方式2:显式指定Looper
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 在主线程处理消息
}
};
// 方式3:指定Looper和回调
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// 处理消息,返回true表示已处理
return true;
}
};
Handler handler = new Handler(Looper.myLooper(), callback);
源码关键点
java
public Handler(@Nullable Callback callback, boolean async) {
// 1. 获取当前线程的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 2. 绑定消息队列
mQueue = mLooper.mQueue;
// 3. 设置回调和异步标志
mCallback = callback;
mAsynchronous = async;
}
消息的发送:Handler提供了两类方法发送消息:
sendMessage系列:发送带有what、arg1、arg2、obj等数据的消息
java
// 发送空消息
handler.sendEmptyMessage(WHAT_CODE);
// 发送延迟消息
handler.sendMessageDelayed(msg, 1000); // 1秒后执行
// 发送指定时间消息
handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + 1000);
// 发送到队列头部(紧急消息)
handler.sendMessageAtFrontOfQueue(msg);
post系列:发送Runnable任务
java
// 立即执行
handler.post(() -> {
// 在主线程执行
updateUI();
});
// 延迟执行
handler.postDelayed(() -> {
// 1秒后执行
doSomething();
}, 1000);
// 带token的post,可以批量取消
Object token = new Object();
handler.postAtTime(runnable, token, SystemClock.uptimeMillis() + 1000);
底层实现post方法最终也会转换成Message
java
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; // Runnable存储在callback字段
return m;
}
当Looper从队列中取出消息后,会调用handler.dispatchMessage():
java
public void dispatchMessage(Message msg) {
// 1. 如果Message有callback(通过post发送的Runnable),优先执行
if (msg.callback != null) {
handleCallback(msg);
} else {
// 2. 如果Handler设置了全局Callback
if (mCallback != null) {
// Callback可以拦截消息处理
if (mCallback.handleMessage(msg)) {
return; // 已处理,不再往下传递
}
}
// 3. 最后调用子类实现的handleMessage
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
处理优先级:Message.callback(Runnable)→ 2. Handler.Callback → 3. Handler.handleMessage()
简单理解,当前handler如果接收到的消息中有Runnable,则执行,否则,如果handler设置了Callback,则执行Callback,否则执行重写的handleMessage方法。

Message的复用机制与内存优化
Message是Handler机制中传递的数据单元,它的复用机制体现了Android对性能的优化。 Message的结构:
java
public final class Message implements Parcelable {
// 标识符,用于区分消息类型
public int what;
// 两个整型参数
public int arg1;
public int arg2;
// 任意对象
public Object obj;
// 目标Handler
/*package*/ Handler target;
// Runnable回调
/*package*/ Runnable callback;
// 下一条消息(链表结构)
/*package*/ Message next;
// 消息池(静态变量)
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
}
为了避免频繁创建Message对象导致内存抖动,Android实现了Message对象池:
java
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
// 从池中取一个Message
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // 清除IN_USE标志
sPoolSize--;
return m;
}
}
// 池为空,创建新对象
return new Message();
}
void recycleUnchecked() {
// 清空消息内容
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
// 放入池中
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
使用方法:
java
// 推荐:使用obtain()获取Message
Message msg = Message.obtain();
msg.what = MSG_UPDATE_UI;
msg.obj = data;
handler.sendMessage(msg);
// 不推荐:直接new Message()
Message msg = new Message(); // 可能造成内存抖动
高级特性与底层机制
同步屏障
同步屏障是一种特殊的消息,用于优先处理异步消息。
- 同步消息:普通通过Handler发送的消息
- 异步消息 :通过
setAsynchronous(true)标记的消息 - 同步屏障:一个target为null的Message,遇到它时,会跳过所有同步消息,只处理异步消息
典型应用:View的绘制
java
// 在ViewRootImpl中
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 1. 设置同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 2. 发送异步的绘制消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
源码中的屏障处理
java
Message next() {
for (;;) {
synchronized (this) {
Message prevMsg = null;
Message msg = mMessages;
// 遇到同步屏障
if (msg != null && msg.target == null) {
// 跳过所有同步消息,只找异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
// ... 处理找到的消息
}
}
}
创建异步消息的方式
java
// 方式1:创建Handler时指定
Handler handler = new Handler(Looper.myLooper(), null, true); // 第三个参数为async
// 方式2:标记已有Message
Message msg = Message.obtain();
msg.setAsynchronous(true);
handler.sendMessage(msg);
// 方式3:post异步任务
handler.post(() -> {
// 异步任务
doAsyncTask();
});
这里易混淆,handler.post()本身只是把Runnable包装成Message发送出去,这个Message是否是异步的,取决于:
- Handler本身是否是异步的(方式1)
- 手动设置Message为异步,即doAsyncTask()是异步的(方式3)
IdleHandler:空闲时执行的任务
IdleHandler允许在消息队列空闲时执行任务。
- 延迟初始化:等主线程空闲时再初始化非紧急组件
- 批量操作:收集多次变化,一次性处理
- 性能监控:检测主线程是否卡顿
使用方法
java
// 添加IdleHandler
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// 在队列空闲时执行
doBackgroundWork();
// 返回true表示继续保留,下次空闲还会执行
// 返回false表示执行一次后移除
return false;
}
});
在MessageQueue的next()方法中:
java
Message next() {
for (;;) {
// ... 检查消息队列
// 空闲时处理IdleHandler
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有IdleHandler,继续阻塞
mBlocked = true;
continue;
}
// 执行IdleHandler
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // 释放引用
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
}
}
Native层的实现
MessageQueue的阻塞和唤醒实际上是在Native层实现的:
java
// Java层
public final class MessageQueue {
// Native层的指针
private long mPtr; // 指向NativeMessageQueue
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
}
// Native层(C++)
class NativeMessageQueue : public MessageQueue {
// 使用Linux的epoll机制实现高效I/O多路复用
Looper* mLooper;
void pollOnce(int timeoutMillis) {
mLooper->pollOnce(timeoutMillis);
}
void wake() {
mLooper->wake();
}
}
为什么要在Native层实现阻塞?
- 效率更高:避免Java层循环空转消耗CPU
- 精准唤醒:使用epoll等系统调用,精确控制线程唤醒
- 统一管理:与Input系统、Binder等共用事件循环
内存泄漏问题与解决方案
Handler内存泄漏是Android开发中最常见的问题之一。
泄露的根本原因
java
public class MainActivity extends AppCompatActivity {
// 非静态内部类隐式持有外部类引用
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 隐式持有MainActivity.this的引用
updateUI();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 发送延迟消息
mHandler.sendEmptyMessageDelayed(0, 60000); // 60秒后执行
// 如果Activity在60秒内被销毁
// 但MessageQueue中还有未处理的消息引用着Handler
// Handler又引用着Activity,导致Activity无法被回收
}
}
解决方案
方案1:静态内部类 + 弱引用(最常用)
java
public class MainActivity extends AppCompatActivity {
private SafeHandler mSafeHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 创建安全的Handler
mSafeHandler = new SafeHandler(this);
}
// 静态内部类,不持有外部类的引用
private static class SafeHandler extends Handler {
// 使用弱引用持有Activity
private final WeakReference<MainActivity> mActivityRef;
public SafeHandler(MainActivity activity) {
super(Looper.getMainLooper());
mActivityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = mActivityRef.get();
if (activity != null && !activity.isFinishing()) {
// Activity还存在,可以安全使用
activity.handleMessage(msg);
} else {
// Activity已被回收,清理消息
removeCallbacksAndMessages(null);
}
}
}
// Activity中的处理方法
private void handleMessage(Message msg) {
switch (msg.what) {
case 1:
updateUI();
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清理Handler
if (mSafeHandler != null) {
mSafeHandler.removeCallbacksAndMessages(null);
}
}
}
方案2:使用Lifecycle + ViewModel(现代Android架构)
kotlin
public class MainActivity extends AppCompatActivity {
// 使用ViewModel + LiveData
class MainViewModel : ViewModel() {
private val handler = Handler(Looper.getMainLooper())
fun doTaskWithDelay(delayMillis: Long, task: () -> Unit) {
handler.postDelayed({
task()
}, delayMillis)
}
override fun onCleared() {
super.onCleared()
// ViewModel销毁时自动清理
handler.removeCallbacksAndMessages(null)
}
}
// Activity中使用
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 安全的延迟任务
viewModel.doTaskWithDelay(30000) {
updateUI() // 如果Activity已销毁,这里不会执行
}
}
}
总结
-
三组件关系:
一个线程 ↔ 一个Looper ↔ 一个MessageQueue ↔ 多个Handler
-
消息循环流程:
Handler发送消息 → MessageQueue入队排序 → Looper循环取出 → 分发回Handler处理
-
内存管理:
- 使用
Message.obtain()复用对象 - 注意Handler内存泄漏问题
- 及时移除不需要的消息
- 使用
-
高级特性:
- 同步屏障用于优先处理异步消息(如UI绘制)
- IdleHandler用于空闲时执行任务
- Native层实现高效阻塞唤醒