在子线程中创建能否创建多个 Handler ,是否会存在多个 Looper?
可以创建多个 Handler ,但不会存在多个 Looper ,在调用
Handler handler;
new Thread(){
public void run(){
Looper.prepare();//实例一个 Looper 加入 ThreadLocal
handler = new Handler();//字线程中创建,可多个
//do something
handler.post(new Runnable(){...});//产生消息,加入队列
Looper.loop();//消息循环
}
}.start();
后只会在该线程中创建一个 Looper 实例,并保存在 ThreadLocal<> 中,多次调用会 Looper.prepare 报错,保证一个子线程只有一个 Looper
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));
}
在该线程中所创建的 Handler 中,所产生的消息 Message 均会加到该线程的 Looper 中的消息队列 Queue 中,所不同的是不同 Handler 所产生的 Message 在它对应的 Handler 的 handlerMessage() 或 callback 中进行处理,故不管创建 Handler 数量多少,均不会对线程或 Looper 产生影响。
//handler 中把 Message 加入队列
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
//Queue 队列,消息加入队列
boolean enqueueMessage(Message msg, long when) {
...//省略
}
Looper 消息循环
- Looper 为静态类,在 APP 启动后实例化 sMainLooper 即主线程 Looper ,可用 Looper.getMainLooper() 与 Looper.myLooper() 进行比较判断当前线程是否为主线程( ui 线程)
- Looper 中有 ThreadLocal <Looper> 用于存放其他线程所产生的 Looper ,保障子线程的消息通信
- Queue 消息队列,用于存放 Handler 产生的 Message ,并在 loop() 循环取出将消息发出,在子线程中,当队列中消息为空时退出循环
可以理解为, Looper 是一个消息容器,接收消息、存放消息、发送消息
Handler 消息产生以及消息处理
- 创建 Handler 可以为空方法,默认线程为当前线程,将产生的消息添加到当前线程的 Looper.queue 中,如果 Looper 不存在将报错
- 处理消息( Message ),在构造方法 handleMessage 中处理,或者定义的 callback 中对消息进行处理
- 消息派发调用 dispatchMessage
Message 消息个体
- 包含 what,arg,obj,target 等基本参数
- 加入队列后,消息派送实际回调 target ,如 handler 的 handleMessage, runnable 的 run 方法。
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.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
//空队列,退出循环
return;
}
//消息处理,回调 target 处理(handleMessage/callback)
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...//省略
msg.recycleUnchecked();//回收
}
}