Android的Handler、MessageQueue、Runnable和Looper的联系(源码选自21版本)
写过一段时间Android代码的程序猿朋友们可能都知道:Looper是一个循环,维护一个消息队列MessageQueue,Handler是一些事件,循环的放入队里中事件然后去处理和回调,但也许还没来得及看一看源码,这块是咋工作的,我这里小做整理,以防以后忘记了,回过来再回味一下【高手欢迎批评指正~】。
在这里,通过下面的分析,我想要回答三个问题:
1.他们四个是怎么联系在一起的?
2.我们在用Handler的时候,一直在脑海中的原理如何从源码级别体会到的呢?
3.应用在运行的时候,它是咋开启的呢?
通过Looper源码的分析,可以找到Handler、MessageQueue和Looper的联系。Looper.java的doc文档也大概介绍了Handler的工作机制,咋一读可能品味不到什么,但捋一遍源码再回头看,其实说的很明白,即:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
Looper.loop();
}
}
从头说起,当我们new一个Handler的时候,即Handler mHandler = new Handler();跟踪Handler.java类,可以看到,它访问了Handler(null, false)方法。这里面传入了Looper,即mLooper = Looper.myLooper()【mLooper肯定不会为null了,否则Handler肯定会创建失败的,这个后面提】;将Looper的MessageQueue传递到了Handler。那么,可以看到了,Looper内一定维护了一个队列了。
我们可能会调用mHandler的post(Runnable)方法,这样就可以执行一段我们想要的操作(当然,也可以使用sendMessage的方式,这个到底有什么区别?)。跟踪post这个方法可以看到,它是将Runnable装换成了Message,同时将runnable传递给Message的callaback参数。它访问了enqueueMessage(),这个Message入队了。
消息入队了,那么它是怎么执行的呢?这个问题由Looper.java来回答。回到Handler的构造函数,它调用了myLooper(),查看这个方法,它是从ThreadLocal里面取了一个Looper。为什么ThreadLocal.get()肯定不会为空呢?首先,可以看看最上面那段LooperThread 的代码,它说:在我们new Handler之前,肯定是系统已经调用了prepare()方法装填了一个Looper了。那究竟这段代码是怎么调用的呢?这个问题就要到ActivityThread.java(附录I、II)这个类里面可以看到。原来,在应用进程的主线程在创建的时候,它就调用了prepare()方法了嘛,代码如下(问题三在这里):
Looper.prepareMainLooper(); ... Looper.loop();
所以,在我们new Hanlder之前,肯定ThreadLocal内已经非空了。看到了,这里调用了loop()方法。查看这个方法,我们可以找到一些信息:
1)取出消息队列中的消息:
Message msg = queue.next();
2)执行我们想要的操作:
msg.target.dispatchMessage(msg);
这里,target就是我们的Handler(这个怎么弄的,可以看obtainMessage())。串联起来了吧, 一般我们就是通过dispatchMessage()来执行我们想要的操作的,对吧。
3)这里有个一直在的循环,循环着处理着消息队列中的操作。
应该还有一个问题,我最开始是使用post来执行一段操作的,虽然说过了将它转换成了Message,但并没有重写dispatchMessage,那么传入到Message的Runnable是咋工作的呢,看一下handler的dispatchMessage,一目了然,使用post的调用方式callback 非空,通过handleCallback访问了message.callback.run();而通过sendMessage的方式callback 可能为空,自然就会走handleMessage()了【代码中还有一点细节,mCallback 也非空的情况,不提了】。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
最后再总结一下,Looper内维护一个循环,当应用ActivityThread第一次访问的时候,开启这个循环,随后,通过Handler将Message(sendMessage或者post传入的由Runnable构建的Message)放入Looper内的MessageQueue。
我感觉差不多说清楚了,暂时我是对Android的消息机制这段比以前认识更多了,还有啥我没说清楚的,可以继续一起研究。不得不提一下,强烈推荐一本书《深入理解Android内核设计思想》,其实可以看到,我的很多认识也是从这本书学到的,不能忘记挖井人!
附录:
[1] ActivityThread简介:http://blog.csdn.net/myarrow/article/details/14223493
[2] Acitvity源码:http://code.taobao.org/svn/cnAndroidSDK/trunk/dev/java/android/app/ActivityThread.java
[3] ThreadLocal:http://blog.csdn.net/aa747604141/article/details/17610269
[4] 《深入理解Android内核设计思想》.林学森