为了深入了解Handler,我们对Handler进行源码分析,看看它究竟是如何完成线程间通信的。
从Handler构造出发
既然是源码分析,为什么突然回到Handler的构造了呢?在我的Handler使用机制及四个组成部分文章中,当我们在非主线程创建handler对象时会出现一个异常。如下:
05-30 15:26:07.490 711-773/com.perry.handler E/AndroidRuntime: FATAL EXCEPTION: Thread-18868
Process: com.perry.handler, PID: 711
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:209)
at android.os.Handler.<init>(Handler.java:123)
at com.perry.handler.OnBackgroundActivity$2.run(OnBackgroundActivity.java:71)
at java.lang.Thread.run(Thread.java:818)
出现这个问题实际上是因为,handler需要Looper对象,来进行内部的全局变量的初始化。
Handler 构造函数.png
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
通过查看源码发现,handler共7个构造函数,使用时只能使用4个,最后都会调用执行如上2个构造方法,而这2个构造方法大同小异,所以我们挑个简短的来看看。发现handler需要looper对象来初始化全局变量Looper及MessageQueue,而MessageQueue是从looper中取出的。MessageQueue用于进程间传递消息,Looper则在该线程内进行消息的派发。
handler.sendMessage
我们通过构造找到了handler的2个协同者,Looper与MessageQueue。那我们发个消息,看看他们都做了些什么!?
无论调用post方法还是sendMessage方法,handler都会从上到下依次调用如下方法。
sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(Message msg, long uptimeMillis)
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
handler.enqueueMessage
此时,到了enqueueMessage方法,就证明这条消息确实发送了,该做下一步处理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
该方法中对message设置了target,将当前的handler存于message中,用于之后message找到自己该去的handler,而后将massage交给MessageQueue。调用queue.enqueueMessage(msg, uptimeMillis)方法,将消息放入到消息队列中。强调一下,这里的queue就是我们前面说到的在构造方法中从looper中取到的消息队列。
Looper.loop()
到了这里,我们发现handler将消息通过MessageQueue放入到消息队列中,那谁把消息取出来进行派发的呢?草丛三兄弟,跳出来两个了,还剩Looper一人默默的蹲在那,那我们来看看他究竟干了啥?!
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block 取出消息,无消息则阻塞
if (msg == null) {
// No message indicates that the message queue is quitting. 没有消息则表明,消息队列正在退出。
return;
}
msg.target.dispatchMessage(msg); // 发送消息, 其中target就是我们之前存入的Handler
}
}
精简了一下该方法,可以看到,Looper通过loop方法,不停的从MessageQueue中取出消息,最终调用了handler的dispatchMessage(msg)方法将消息派发给handler自己。
handler.dispatchMessage
最后,消息派发给handler,会先判断msg的callback对象(实际上是runnable对象)是否为空,如果不为空则执行handleCallback(msg)方法,callback.run();而如果为空就会调用handleMessage方法,完成回调。(这也是为什么我们构造Handler时,实现了抽象方法handleMessage而post(runnable)时,为什么不调用handleMessage方法的原因)。
// msg.callback实际上是Runnable对象
// mCallback是一个实现了handleMessage(msg)的回调接口
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); // msg.callback.run();
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
那么来画个图总结一下。
图中我们从主线程中创建Handler,在子线程中发送消息,而这一系列的配合操作,需要仔细看图,不懂的可以回看文章。
上一篇:Handler使用机制及四个组成部分
网友评论