在 Android 中,Handler 中的代码是由创建该 Handler 时绑定的 Looper 所在的线程执行的。这是 Android 线程通信模型的核心机制,下面我将详细解释其原理和使用场景。
核心原理图解
执行场景分析
1. 主线程 Handler(UI 线程)
// 在主线程创建
Handler mainHandler = new Handler(Looper.getMainLooper());
// 在任何线程发送任务
new Thread(() -> {
mainHandler.post(() -> {
// 这段代码在主线程执行
textView.setText("Updated from UI thread");
});
}).start();
特点:
使用
Looper.getMainLooper()
绑定主线程适合更新 UI
执行线程:主线程(UI 线程)
2. 子线程 Handler(工作线程)
// 创建带 Looper 的工作线程
HandlerThread workerThread = new HandlerThread("Worker");
workerThread.start();
// 绑定工作线程的 Looper
Handler workerHandler = new Handler(workerThread.getLooper());
// 发送任务
workerHandler.post(() -> {
// 这段代码在 workerThread 执行
performLongOperation(); // 耗时操作
});
特点:
绑定特定子线程的 Looper
适合后台任务
执行线程:创建 Looper 的子线程
3. 当前线程 Handler
new Thread(() -> {
Looper.prepare(); // 初始化当前线程的 Looper
Handler threadHandler = new Handler(); // 默认绑定当前线程
threadHandler.post(() -> {
// 在当前子线程执行
Log.d("CurrentThread", Thread.currentThread().getName());
});
Looper.loop(); // 启动消息循环
}).start();
特点:
默认绑定创建 Handler 的线程
需要手动
Looper.prepare()
和Looper.loop()
执行线程:创建 Handler 的线程
底层机制详解
消息处理流程
关键源码分析
// Handler.java
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 执行 Runnable
msg.callback.run(); // 在Looper所在线程执行
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); // 在Looper所在线程执行
}
}
// Looper.java
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
// 关键:在Looper所在线程执行
msg.target.dispatchMessage(msg);
}
}
执行线程判断表
Handler 创建方式 | 代码执行线程 | 典型使用场景 |
---|---|---|
new Handler(Looper.getMainLooper()) |
主线程 | UI 更新 |
new Handler(handlerThread.getLooper()) |
指定子线程 | 后台任务处理 |
new Handler() (在主线程) |
主线程 | 默认 UI 处理 |
new Handler() (在子线程 + Looper) |
创建 Handler 的子线程 | 线程内任务调度 |
view.post(runnable) |
主线程 | View 相关操作 |
常见问题与解决方案
Q:如何在子线程更新 UI?
// 方案1:使用主线程 Handler
new Thread(() -> {
// 后台工作
runOnUiThread(() -> {
// 在主线程更新 UI
textView.setText("Done");
});
}).start();
// 方案2:使用 View.post()
imageView.post(() -> {
imageView.setImageBitmap(bitmap);
});
Q:Handler 内存泄漏
// 正确做法:静态内部类 + 弱引用
private static class SafeHandler extends Handler {
private final WeakReference<Activity> weakActivity;
SafeHandler(Activity activity) {
super(Looper.getMainLooper()); // 明确绑定主线程
this.weakActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
Activity activity = weakActivity.get();
if (activity != null) {
// 安全操作
}
}
}
常见用法
明确指定 Looper:
// 总是显式指定 Looper new Handler(Looper.getMainLooper()); // 不依赖创建位置
UI 操作使用主线程 Handler:
// 专用 UI Handler private final Handler uiHandler = new Handler(Looper.getMainLooper()); void updateUI(String text) { uiHandler.post(() -> textView.setText(text)); }
后台任务使用工作 Handler:
// 创建工作线程 Handler private Handler workerHandler; void initWorker() { HandlerThread thread = new HandlerThread("Worker"); thread.start(); workerHandler = new Handler(thread.getLooper()); } void processData(Data data) { workerHandler.post(() -> { // 耗时操作 }); }
避免在子线程创建无 Looper 的 Handler:
// 错误示例(会崩溃) new Thread(() -> { Handler handler = new Handler(); // 抛出异常! }).start();
总结
Handler 中的代码在哪个线程执行?
Handler 中的代码执行线程取决于创建 Handler 时绑定的 Looper:
主线程执行:
使用
new Handler(Looper.getMainLooper())
创建通过
View.post()
发送的任务在主线程创建的默认 Handler
子线程执行:
绑定子线程 Looper 的 Handler(如 HandlerThread)
在子线程创建并初始化了 Looper 的 Handler
执行机制:
所有发送到 Handler 的消息/任务,都会被放入关联的 MessageQueue
Looper 在绑定线程中不断循环取出消息
最终在 Looper 所在线程执行
dispatchMessage()