http://teok.iteye.com/blog/920562
看过冷冰的Android核心分析第十一篇:Android GWES之消息系统,我得到了一张重要的图:

对照源码看这张图之后,我发现冷冰已经总结的很清晰。我补充我认识到的另外几点看法和疑问:
1.MessageQueue对外来说基本是不可见的,我们要为自己的程序添加消息处理机制时无需关心的(当然无需关心,这一点好勉强,^_^)
2.在Looper中有这么一段
private static final ThreadLocal sThreadLocal = new ThreadLocal();
因此,即便在一个VM实例中存在多个消息处理框架,线程相关的资源依旧是共享的。(不过ThreadLocal等概念我还得普及一下)
3. 阅读Handler代码发现一个很有趣的地方,先看代码:
在Message中有这么一段:
/*package*/ Runnable callback;
在Handler中有这么一个方法:
private final void handleCallback(Message message) {
message.callback.run();
}
而这个handleCallback方法是在handleMessage时调用的:
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
- /**
- * Handle system messages here.
- */
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
哈,这让我想起了以前写js代码时那种回调风格。。我以前看到的或者用到的回调大多是自己定义一个接口,折腾了一圈才发现,原来有现成的啊,竟然不懂得用。。
4. 从Message类中的next变量和obtain方法看出,Message从结构上来看,就像一个链表,没有方向,没有优先级概念(那如果消息存在优先级的话,这个框架还能搞定吗?当然是不能)。试想一下,在GWES模型中,会不会出现一种情况,某些事件的优先级要高于其它而要优先处理的呢?如果碰到这种情况该怎么处理?
今天看相关源码发现,Android消息处理框架,没有优先级这一说。我们在sendMessage的时候最多能加上一个delay time作为参数,所以框架的使用者如果需要达到某些消息优先处理,那么可以通过这个delay time来实现。(是不是有点别扭,没事,习惯了就好……但,还是有点别扭)
考虑一下Android手机的系统特性,每个手机都会一个菜单键、Home键和back键,那么在什么情况下会存在一些优先级较高的消息呢,我目前还没想出来,因为在一个Activity里面,所有view component的地位都应该是相等的,所以每个component的消息处理也应该是同级的,如果某个应用中需要处理一些特别的(例如定时、延迟)消息,可以采用Task来处理定时任务,延迟也只要加上delay time参数即可。对于back键的处理Activity是单独开来的,开发者需要在onBackPresssed中自行处理,menu键和这是一样的,Home键开发者根本没法控制的,系统会自动处理(onPause --> onStop)。其实这几个键事件也是我目前能想到的需要特别处理的地方。
5. 首先来看一段代码:
- final boolean enqueueMessage(Message msg, long when) {
- if (msg.when != 0) {
- throw new AndroidRuntimeException(msg
- + " This message is already in use.");
- }
- if (msg.target == null && !mQuitAllowed) {
- throw new RuntimeException("Main thread not allowed to quit");
- }
- synchronized (this) {
- if (mQuiting) {
- RuntimeException e = new RuntimeException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- } else if (msg.target == null) {
- mQuiting = true;
- }
- msg.when = when;
- //Log.d("MessageQueue", "Enqueing: " + msg);
- Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {
- msg.next = p;
- mMessages = msg;
- this.notify();
- } else {
- Message prev = null;
- while (p != null && p.when <= when) {
- prev = p;
- p = p.next;
- }
- msg.next = prev.next;
- prev.next = msg;
- this.notify();
- }
- }
- return true;
- }
这段代码是MessageQueue中将某个message加入消息队列的方法,这里我注意到两点:
1. 没有使用容器类来充当一个message pool,而是每个message对象都会有一个next字段用以引用它的下一个,所以message是以对象间链式的引用来存储的(message会被Looper处理,所以不用担心对象会释放掉造成数据丢失;没有用到集合类,简化了数据结构和操作)
2.那个while循环是进行排序的,它会对每个新进来的message对象按照when(就是delay time)进行排序,因为是链式数据结构,所以效率相当高(不过我没测试过有多高)
引申:这个算法让我对数据结构又有一点新的认识。以前我总是条件反射的以为,任何数据都会以某种容器来存储(我惯用ArrayList、Map等什么的),但是我却忽视了一点,什么是容器,我曾经看过ArrayList或者其它的代码,它们内部都会有一个数组结构来存储数据,如果数据超出数组边界,那么就新创建一个数组把原来的数据拷贝进去(System.arrayCopy)再把旧数组替换掉(Map什么的我具体忘记了,但是我估计也不出这左右),所以,数组是最基本结构;除此之外,任何new出来的对象都应该是某种数据结构,它们用字段存储数据,只是它们没有名字而已(像List,Map等这样的数据结构领域的名字)。到这,就不难理解为什么googler可以用对象之间的相互引用来实现某种数据存储,因为,任何这种那样的方式的本质是没有改变的:一种映射,语言标记到计算机存储之间的映射,通过使用标记就能明确访问这个标记所对应的计算机上存储的数据。