Android消息处理框架:Looper,Handler,MessageQueue

Android消息处理框架:Looper,Handler,MessageQueue ...
看过冷冰的Android核心分析第十一篇:Android GWES之消息系统,我得到了一张重要的图:
621x378
对照源码看这张图之后,我发现冷冰已经总结的很清晰。我补充我认识到的另外几点看法和疑问:

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 --$amp;>amp;$nbsp; 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可以用对象之间的相互引用来实现某种数据存储,因为,任何这种那样的方式的本质是没有改变的:一种映射,语言标记到计算机存储之间的映射,通过使用标记就能明确访问这个标记所对应的计算机上存储的数据。

你可能感兴趣的:(messagequeue)