在Android开发中,Handler是消息处理机制的核心组件之一。它允许我们在不同线程之间发送和处理Message或Runnable对象。默认情况下,Handler会绑定到创建它的线程的Looper上。这意味着在主线程(UI线程)中创建的Handler会自动关联到主线程的Looper,而在子线程中创建Handler则需要特别注意。
关键点:每个Handler必须绑定一个Looper,而Looper是与线程绑定的。主线程默认有Looper,但普通子线程没有。
在实际开发中,我们可能会遇到这些场景:
在子线程中创建Handler需要遵循以下流程:
java复制// 步骤1:创建并启动子线程
Thread workerThread = new Thread(new Runnable() {
@Override
public void run() {
// 步骤2:准备Looper
Looper.prepare();
// 步骤3:创建Handler
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
// 步骤4:启动消息循环
Looper.loop();
}
});
workerThread.start();
这个方法会为当前线程创建一个Looper对象。Looper内部维护了一个MessageQueue,它是消息存储和分发的核心。
注意:每个线程只能调用一次prepare(),重复调用会抛出RuntimeException。
获取当前线程关联的Looper对象。在prepare()之后调用才能获取到非null值。
启动消息循环,这个方法会阻塞当前线程,不断从MessageQueue中取出消息并分发给对应的Handler处理。
java复制public class HandlerInThreadDemo {
private Handler workerHandler;
public void startWorkerThread() {
new Thread(() -> {
Looper.prepare();
workerHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
Log.d("WorkerHandler", "Received message: " + msg.what);
// 实际业务处理
}
};
// 发送测试消息
workerHandler.sendEmptyMessage(1001);
Looper.loop();
}, "WorkerThread").start();
}
public void sendMessageToWorker(int what) {
if (workerHandler != null) {
workerHandler.sendEmptyMessage(what);
}
}
}
错误现象:
code复制java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
解决方案:确保在创建Handler前调用Looper.prepare()。
现象:Handler无法接收到任何消息。
原因:没有启动消息循环,MessageQueue中的消息永远不会被处理。
一个线程可以有多个Handler,它们共享同一个Looper和MessageQueue:
java复制Looper.prepare();
Handler handler1 = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理类型1的消息
}
};
Handler handler2 = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理类型2的消息
}
};
Looper.loop();
可以通过重写dispatchMessage()方法来自定义消息分发逻辑:
java复制Handler customHandler = new Handler(Looper.myLooper()) {
@Override
public void dispatchMessage(Message msg) {
if (msg.getCallback() != null) {
// 优先处理Runnable
msg.getCallback().run();
} else {
// 其次处理普通消息
super.dispatchMessage(msg);
}
}
};
Android提供了HandlerThread类来简化实现:
java复制HandlerThread handlerThread = new HandlerThread("WorkerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
优势:
| 机制 | 适用场景 | 特点 |
|---|---|---|
| Handler | 线程内/间通信 | 精确控制、可延时 |
| AsyncTask | 简单后台任务 | 已废弃,不推荐使用 |
| Executor | 线程池管理 | 适合批量任务 |
| LiveData | 数据观察 | 生命周期感知 |
通过设置消息的priority字段可以影响处理顺序:
java复制Message msg = handler.obtainMessage();
msg.what = MSG_TYPE;
msg.arg1 = 100;
msg.setAsynchronous(true); // 设置为异步消息
handler.sendMessage(msg);
java复制// 发送延时3秒的消息
handler.sendEmptyMessageDelayed(MSG_DELAYED, 3000);
// 在适当时候移除未执行的延时消息
handler.removeMessages(MSG_DELAYED);
主线程向工作线程发送消息:
java复制// 在工作线程中
Looper.prepare();
workerHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理来自主线程的消息
}
};
Looper.loop();
// 在主线程中
runOnUiThread(() -> {
workerHandler.sendEmptyMessage(MSG_FROM_UI);
});
java复制// 获取Looper的MessageQueue
Looper looper = workerHandler.getLooper();
looper.setMessageLogging(new Printer() {
@Override
public void println(String x) {
// 分析消息处理耗时
}
});
java复制StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls()
.penaltyLog()
.build());
推荐使用静态内部类+弱引用的方式:
java复制private static class SafeHandler extends Handler {
private final WeakReference<Activity> activityRef;
SafeHandler(Activity activity, Looper looper) {
super(looper);
this.activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
Activity activity = activityRef.get();
if (activity == null || activity.isFinishing()) {
return;
}
// 安全处理消息
}
}
虽然Handler仍然有效,但在新项目中可以考虑:
不过理解Handler机制仍然是Android开发的重要基础,特别是在维护旧代码或需要精细控制线程行为时。