Handler和Looper的关系
- 基本概念
Looper(循环器):
●负责管理消息队列(MessageQueue)
●不断从消息队列中取出消息并分发给对应的Handler处理
●每个线程只能有一个Looper
Handler(处理器):
●负责发送和处理消息
●与特定的Looper关联
●可以发送消息到消息队列,也可以处理从消息队列中取出的消息
- 关系说明
Handler ←→ Looper ←→ MessageQueue
●Handler依赖Looper:Handler需要绑定一个Looper才能工作
●Looper管理消息队列:Looper负责从MessageQueue中取出消息
●Handler处理消息:Looper将消息分发给对应的Handler处理
- 工作流程
●创建Looper:线程调用Looper.prepare()创建Looper
●启动循环:调用Looper.loop()开始消息循环
●Handler发送消息:Handler调用sendMessage()或post()发送消息到队列
●Looper分发消息:Looper从队列取出消息,调用Handler的handleMessage()方法
- 在子线程中创建Handler
// 在子线程中创建Handler
class WorkerThread extends Thread {
private Handler handler;
@Override
public void run() {
// 1. 准备Looper
Looper.prepare();
// 2. 创建Handler(自动绑定当前线程的Looper)
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
switch (msg.what) {
case 1:
// 处理消息类型1
break;
}
}
};
// 3. 启动消息循环
Looper.loop();
}
public void sendMessage() {
// 发送消息
handler.sendEmptyMessage(1);
}
}
其中Looper.prepare() 和Looper.loop()是必须的,Looper.prepare() 会自动为当前线程创建一个Looper对象,而Looper.loop()会将创建好的Looper运行起来,如果没有,则会抛出异常。
// Looper.prepare() 的源码逻辑
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));
}
上述是Looper.prepare()创建Looper的过程,可以看出,会先进行检验当前是否存在Looper,如果存在则抛出RuntimeException异常,如果不存在,则创建一个新的Looper。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
...
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
上述是Looper.loop()的源码,可以看出,一开始会检测当前线程是否存在一个Looper,如果不存在,则抛出RuntimeException异常。
- 主线程的特殊性
主线程(UI线程)默认就有Looper,所以可以直接创建Handler:
// 主线程中直接创建Handler
Handler mainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 处理消息
}
};
Handler线程间通信
- 子线程 → 主线程
public class MainActivity extends AppCompatActivity {
private Handler mainHandler; // 绑定主线程的Looper
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 在主线程创建Handler,自动绑定主线程的Looper
mainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 这个代码在主线程执行
updateUI();
}
};
// 启动子线程
new Thread(() -> {
// 子线程执行耗时操作
String result = doHeavyWork();
// 发送消息到主线程
mainHandler.post(() -> {
// 这个代码在主线程执行
updateUI(result);
});
}).start();
}
}
- 主线程 → 子线程
public class WorkerThread extends Thread {
private Handler workerHandler; // 绑定子线程的Looper
@Override
public void run() {
// 1. 准备子线程的Looper
Looper.prepare();
// 2. 创建Handler,绑定到当前子线程的Looper
workerHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 这个代码在子线程执行
processTask(msg.obj.toString());
}
};
// 3. 启动消息循环
Looper.loop();
}
// 提供方法让主线程发送消息给子线程
public void sendTask(String task) {
if (workerHandler != null) {
Message msg = Message.obtain();
msg.obj = task;
workerHandler.sendMessage(msg);
}
}
}
// 在主线程中使用
public class MainActivity extends AppCompatActivity {
private WorkerThread workerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 启动工作线程
workerThread = new WorkerThread();
workerThread.start();
// 主线程发送任务给子线程
findViewById(R.id.button).setOnClickListener(v -> {
workerThread.sendTask("处理这个任务");
});
}
}
- 子线程 → 子线程
public class ThreadA extends Thread {
private Handler threadBHandler; // 绑定到线程B的Handler
public ThreadA(Handler threadBHandler) {
this.threadBHandler = threadBHandler;
}
@Override
public void run() {
// 线程A的工作
while (true) {
// 做一些工作
String result = doWork();
// 发送结果给线程B
threadBHandler.post(() -> {
// 这个代码在线程B中执行
processResult(result);
});
Thread.sleep(1000);
}
}
}
public class ThreadB extends Thread {
private Handler threadBHandler;
@Override
public void run() {
Looper.prepare();
// 创建Handler,绑定到线程B
threadBHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 在线程B中处理消息
System.out.println("线程B收到消息: " + msg.obj);
}
};
Looper.loop();
}
public Handler getHandler() {
return threadBHandler;
}
}
// 使用示例
public class ThreadCommunicationExample {
public void startThreads() {
// 启动线程B
ThreadB threadB = new ThreadB();
threadB.start();
// 等待线程B的Handler准备就绪
while (threadB.getHandler() == null) {
Thread.sleep(10);
}
// 启动线程A,并传入线程B的Handler
ThreadA threadA = new ThreadA(threadB.getHandler());
threadA.start();
}
}
- 多线程Handler通信架构
public class MultiThreadHandler {
private Handler mainHandler; // 主线程Handler
private Handler networkHandler; // 网络线程Handler
private Handler dbHandler; // 数据库线程Handler
public MultiThreadHandler() {
// 主线程Handler
mainHandler = new Handler(Looper.getMainLooper());
// 启动网络线程
startNetworkThread();
// 启动数据库线程
startDatabaseThread();
}
private void startNetworkThread() {
new Thread(() -> {
Looper.prepare();
networkHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 在网络线程处理网络请求
String response = performNetworkRequest((String) msg.obj);
// 发送结果给主线程
mainHandler.post(() -> {
updateUI(response);
});
}
};
Looper.loop();
}).start();
}
private void startDatabaseThread() {
new Thread(() -> {
Looper.prepare();
dbHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 在数据库线程处理数据操作
saveToDatabase((String) msg.obj);
// 发送结果给主线程
mainHandler.post(() -> {
showSaveSuccess();
});
}
};
Looper.loop();
}).start();
}
// 主线程发送网络请求
public void requestData(String url) {
if (networkHandler != null) {
Message msg = Message.obtain();
msg.obj = url;
networkHandler.sendMessage(msg);
}
}
// 主线程保存数据
public void saveData(String data) {
if (dbHandler != null) {
Message msg = Message.obtain();
msg.obj = data;
dbHandler.sendMessage(msg);
}
}
}
消息队列为空的情况下,Looper处于什么状态
- Looper的核心状态:等待状态
当消息队列为空时,Looper处于等待状态(WAITING),具体表现为:
// Looper.loop() 的核心逻辑
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
// 关键:当队列为空时,next()会阻塞
Message msg = queue.next(); // 这里会阻塞等待
if (msg == null) {
return; // 只有Looper被退出时才返回null
}
// 处理消息
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
- MessageQueue.next() 的阻塞机制
// MessageQueue.next() 的简化逻辑
Message next() {
for (;;) {
// 检查是否有消息
if (mMessages != null) {
// 有消息,返回消息
return mMessages;
}
// 没有消息,进入等待状态
nativePollOnce(ptr, nextPollTimeoutMillis);
// 这里会调用native方法,让线程进入等待状态
}
}
当Handler发送消息 → MessageQueue.enqueueMessage() → native层的wake()方法,wake()会向等待的线程发送信号(如写管道、futex唤醒等),等待的线程被唤醒,nativePollOnce返回,Java层继续处理消息。
Handler/Looper/MessageQueue的线程安全机制
- 设计原则
●每个Looper/MessageQueue只属于一个线程
Handler只能处理它所绑定线程的消息队列,消息的处理始终在同一个线程内完成。
●消息的入队是线程安全的
任何线程都可以安全地向Handler发送消息(即向MessageQueue入队)。
●消息的出队和处理只在Looper线程内
只有Looper线程会不断从MessageQueue取出消息并处理。
- 消息入队的线程安全
// MessageQueue.enqueueMessage()
synchronized (this) {
// ... 省略部分代码 ...
// 将消息插入队列
msg.next = p;
prev.next = msg;
// ... 省略部分代码 ...
}
synchronized保证了多线程同时入队时的互斥,防止数据竞争。
- 消息出队和处理
只有Looper线程会调用MessageQueue.next(),因此出队和处理消息不需要额外加锁,天然线程安全。
- 常见线程安全误区
●误区1:Handler可以跨线程处理消息
实际上,Handler只能在它绑定的Looper线程处理消息。
●误区2:Handler的成员变量天然线程安全
只有消息队列是线程安全的,Handler自己的成员变量如果被多个线程访问,需要自己加锁或用线程安全的数据结构。
- 进阶:HandlerThread的线程安全
HandlerThread内部自动为你创建了一个带Looper的线程,Handler绑定到这个线程,消息的处理天然线程安全。
HandlerThread thread = new HandlerThread("MyThread");
thread.start();
Handler handler = new Handler(thread.getLooper());