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

来源:互联网 发布:淘宝客服外包 编辑:程序博客网 时间:2024/06/06 13:19

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时调用的: 
Java代码  收藏代码
  1. /** 
  2.      * Subclasses must implement this to receive messages. 
  3.      */  
  4.     public void handleMessage(Message msg) {  
  5.     }  
  6.       
  7.     /** 
  8.      * Handle system messages here. 
  9.      */  
  10.     public void dispatchMessage(Message msg) {  
  11.         if (msg.callback != null) {  
  12.             handleCallback(msg);  
  13.         } else {  
  14.             if (mCallback != null) {  
  15.                 if (mCallback.handleMessage(msg)) {  
  16.                     return;  
  17.                 }  
  18.             }  
  19.             handleMessage(msg);  
  20.         }  
  21.     }  

哈,这让我想起了以前写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.  首先来看一段代码: 
Java代码  收藏代码
  1. final boolean enqueueMessage(Message msg, long when) {  
  2.         if (msg.when != 0) {  
  3.             throw new AndroidRuntimeException(msg  
  4.                     + " This message is already in use.");  
  5.         }  
  6.         if (msg.target == null && !mQuitAllowed) {  
  7.             throw new RuntimeException("Main thread not allowed to quit");  
  8.         }  
  9.         synchronized (this) {  
  10.             if (mQuiting) {  
  11.                 RuntimeException e = new RuntimeException(  
  12.                     msg.target + " sending message to a Handler on a dead thread");  
  13.                 Log.w("MessageQueue", e.getMessage(), e);  
  14.                 return false;  
  15.             } else if (msg.target == null) {  
  16.                 mQuiting = true;  
  17.             }  
  18.   
  19.             msg.when = when;  
  20.             //Log.d("MessageQueue", "Enqueing: " + msg);  
  21.             Message p = mMessages;  
  22.             if (p == null || when == 0 || when < p.when) {  
  23.                 msg.next = p;  
  24.                 mMessages = msg;  
  25.                 this.notify();  
  26.             } else {  
  27.                 Message prev = null;  
  28.                 while (p != null && p.when <= when) {  
  29.                     prev = p;  
  30.                     p = p.next;  
  31.                 }  
  32.                 msg.next = prev.next;  
  33.                 prev.next = msg;  
  34.                 this.notify();  
  35.             }  
  36.         }  
  37.         return true;  
  38.     }  

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

0 0
原创粉丝点击