一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
c.loop()
Looper在通过prepare(x)后需要执行loop()来将消息进行循环处理;
public static void loop() {
final Looper me = myLooper();
//如果Looper为null,则抛出异常
//主线程启动时会创建Looper,所以主线程创建多个Handler时,通过sThreadLocal.get()获取的是同一个Looper。
//如果非主线程创建Handler,需要先执行Looper.prepare()来创建Looper,否则loop()时会抛异常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//不断的循环取消息,如果没有消息则等待
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// message为空,说明调用了quit(),会return继而退出loop()
return;
}
try {
//处理消息
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.......
//消息处理完后释放
msg.recycleUnchecked();
}
}
可以看到,在loop()内部会先通过myLooper()获取到对应线程的Looper,继而获取到对应的MessageQueue,接下来不断的去读取MessageQueue内部的消息,然后进行处理;
没有消息时,会一直阻塞在Message msg = queue.next(),等待MessageQueue分发消息;
有消息时,调用Handler来处理消息;
消息处理完后进行recycleUnchecked()处理。
d.quitSafely()
子线程在没有消息需要处理时,需要退出looper,否则一直block在loop()中的Message msg = queue.next();
public void quitSafely() {
mQueue.quit(true);
}
前面讲到,子线程的Looper是可以退出的,通过调用以上方法来退出,其实最终调用的MessageQueue的quit(),消息队列退出了,就没有消息进行处理了,Looper也就不需要轮询了,也就可以退出了。
2.Handler
a.Handler()
//默认主线程
public Handler() {
this(null, false);
}
//使用线程已经创建好的Looper
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Callback callback, boolean async) {
......
//获取上面主线程创建的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//获取上面主线程Looper里面创建的MessageQueue
mQueue = mLooper.mQueue;
//默认为null,通过handler中的handleMessage来处理
mCallback = callback;
.......
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
通过以上可以看到,在Handler的构造方法会分为几类:
无参:代表默认使用当前线程的handler(一般是主线程),会通过Looper.myLooper()来获取到对应的Looper,如果Looper为null的话会抛异常,所以子线程使用Handler需要先通过Looper.prepare()来创建Looper;
传入Looper参数:直接使用传入的Looper(使用HandlerThread时这样操作);
从Looper中获取到对应的MessageQueue,Callback默认为null,通过实现的handleMessage()来处理。
可以看到,在创建Handler时会通过myLooper()来获取到对应线程的Looper,此时两者建立了联系;
b.sendMessage()
当调用Handler的sendMessagexx()发送消息时,最终都会调用到sendMessageAtTime(),内部就是将message加入到messagequeue中。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//获取MessgeQueue(即主线程的MessageQueue,上面已经创建完成)
MessageQueue queue = mQueue;
if (queue == null) {
return false;
}
//将message加入队列
return enqueueMessage(queue, msg, uptimeMillis);
}
调用post(Runnable)也会将runnable转换为message:
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
通过post(Runnable r)方式,最终也会转换为Message方式,将Runnable赋值给callback,有消息到来时,调用run方法来UI更新逻辑。
c.enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到,在该方法内部主要执行了三件事:
1.将Handler对象赋值给msg.target,从而message持有Handler对象的引用;
2.如果mAsynchronous为true,会执行setAsynchronous(true)将其设置为异步消息,跟消息屏障一起使用,处理优先级高的消息(UI绘制);
3.调用MessageQueue内的enqueueMessage()最终把发送的Message放进了主线程的MessageQueue里面进行循环;