http://blog.csdn.net/xiang_j2ee/article/details/7042298

原文链接:http://blog.csdn.net/thl789/article/details/6601558

本文解析Android如何利用Handler/Thread/Looper以及MessageQueue来实现消息机制的内部实现。知道了它的内部实现机理之后,以后再遇到使用它们时候的任何问题就驾轻就熟、迎刃而解了。

Android利用执行在HandlerThread线程中的Looper的相应消息分发/处理,与其他线程中的消息发送结合,实现完整的消息处理机制。本文首先介绍这些消息处理过程中的参与者之间的关系,然后结合WifiService消息处理的实际实例,讲解消息处理的全过程,最后还从线程视图的角度,重新审视一下线程同步模型。


一、HandlerThread/Looper/MessageQueue的前世今生

下图是从Froyo从抽取出的HandlerThread、Looper和MessageQueue的关系图。他们被定义在package android.os。

图一:HandlerThread/Looper/MessageQueue实例关系

HandlerThread是一个Thread,继承自Thread。它保留着对Looper实例的引用,不过这里还看不到HandlerThread、Looper和MessageQueue如何实例化,这要到二、HandlerThread/Looper/MessageQueue实例化之后才能看清如何实现的。

一看便知,Looper的构造函数是私有的,外界无法直接实例化之;要实例化,只有通过Looper::prepare()。这样HandlerThread就与Looper建立了对应关系。对如何建立的是不是已经迫不及待了,那就接着看下一小节。

二、HandlerThread/Looper/MessageQueue实例化

上一节只是看了HandlerThread、Looper和MessageQueue之间的静态视图关系,他们具体如何实例化的,还要看动态的实例初始化过程。

图二:HandlerThread/Looper实例化


  • HandlerThread是一个Thread,在它被实例化并执行start()[序列1&2]之后,它的run()方法会在它自己的线程空间执行[序列3]。
  • 上节已经提到了Looper的实例化是通过Looper::prepare实现的,图中可以看到Looper::prepare()正是在HandlerThread::run()中被调用而实例化[序列4&5]的。
  • MessageQueue是在Looper的私有构造函数Looper()中实例化的。

总结一下,HandlerThread是被显式地通过new创建的实例,而与它绑定在一起的Looper是在HandlerThread的执行过程中被实例化的,相应的MessageQueue也是在这个过程中实例化的。

三、Looper::loop分发处理消息

上节重点讲了HandlerThread/Looper的实例化过程,它发生在Thread::run()这也是线程运行的关键,从图二也看到了Looper::loop()这个消息处理的核心正是在这里执行的,下面就看看它到底做了什么。

图三:Looper::loop()处理


图中的所有序列是发生在一个无限循环体while (true) {} 中的。

  • mQueue:MessageQueue是Looper保留的一份引用,通过它的next()[序列1]获取MessageQueue中的下一个要处理的消息,这个过程中如果没有相应的消息,执行它的线程会用this.wait()释放它所拥有的MessageQueue的对象锁而等待。
  • 一旦有消息到来[序列2],Looper会用获得的Message的Handler(msg.target)来分发处理消息[序列3&4]。消息处理完之后,还要回收[序列5]。

四、Handler实现具体消息处理

在Looper::loop()消息处理的顺序图里看到了Handler,这个消息分发处理的参与者。下面结合WifiHandler这个具体的Handler看它如何参与到消息的发送、分发和处理的。


4.1 Handler实例化

WifiService中定义了如下的WifiHandler。

图四、消息的发送、分发、处理者Handler


看Handler的构造函数是需要Looper的,从上面的分析知道,Looper是在HandlerThread执行中实例化的,Looper实例如何获得的呢?看图一&图二,知道HandlerThread保留着Looper的应用mLooper,并可通过getLooper()被外面获取。而Handler的mQueue: MessageQueue可以通过mLooper.mQueue获得。


所以,Wifi的HandlerThread,WifiHandler可以这样实例化:

view plain copy to clipboard
  1. HandlerThreadwifiThread=newHandlerThread("WifiService");
  2. wifiThread.start();
  3. mWifiHandler=newWifiHandler(wifiThread.getLooper());
[java] view plain copy
  1. HandlerThreadwifiThread=newHandlerThread("WifiService");
  2. wifiThread.start();
  3. mWifiHandler=newWifiHandler(wifiThread.getLooper());

4.2 消息发送

图五、消息发送

通过Message::obtain()可以建立起Message和Target/Handler,what之间的关系,并得到一个Message msg[序列1&2];然后通过msg.sendToTarget()就可以用Handler来具体发送消息了[序列3&4];通过一系列的调用,最后会通过MessageQueue::enqueueMessage()把消息放到mMessages上[序列7],还会通过this.notify()通知正在等待新消息的线程,重新拥有MessageQueue的对象锁,而处理该消息。

图六、MessageQueue与Message的关系

至此,消息的发送,分发,处理基本上介绍完毕。


4.3 消息处理

而要具体处理消息,从图三的序列4就可知道,整个框架的最后消息的处理是通过Handler::handleMessager(msg: Message)来完成。所以如果有自己具体要处理的消息,只要override Handler的handleMessage(msg: Message)方法,并加入自己特定的对消息的处理即可。


要处理消息,就看看Message的属性里都有什么。

图七、Message属性


重点关注public属性what是区分具体什么消息;可以带参数arg1, arg2。

五、重新审视

5.1 应用指南

上面介绍了消息处理的全过程,这些对于只是用来发送和处理消息的应用者来说,可能有些繁杂,这里梳理一下从应用者角度看,怎么使用之。

其实四、Handler实现具体消息处理中的WifiService就是一个典型的应用场景。

实现一个Handler的子类,并Override handleMessage()方法,亦即,实现消息处理函数handleMessage()。然后分别创建HandlerThread和Hanlder继承类的实例。这样就可以如4.2里那样发消息了,而消息处理在handleMessage()中进行。

从应用者角度看,Looper和MessageQueue是消息处理的内部机制,可以不关注它的实现细节(唯一要知道的,Handler实例化的时候,需要通过HandlerThread获得Looper的实例,从而可以传递给Handler)。


5.2 线程角度

下面再从线程的角度看一下,消息处理过程中参与的线程,以及这些线程之间的同步。

显然的,这里有线程HandlerThread的参与,而且Looper::loop()就是执行在HandlerThread的run()方法里,也就是在HandlerThread里执行,这也就是说消息的分发处理和执行是在HandlerThread的线程上下文中。另外,还有至少一个线程存在,也就是创建了HandlerThread的线程B,以及执行消息发送的线程C,B和C有可能是同一线程。

消息的发送是在另外一个线程里,就是因为有了多个线程的存在,才有了线程的同步操作。可再次关注一下图三和图五中实现线程同步的Java原语wait()/notify()。

结束语

写本文的初衷并不是为了写它而写它,是在研究Android中的Wifi实现时,遇到了实现Wifi的各种具体操作都是通过消息来实现的,就想探讨一下ANDROID消息处理机制,这样就边看边用ROSE画了图,等到消息的发送/接收/处理的过程都看完了,再回头看一下整个UML图,这不就整个一完整的消息处理机制嘛!

工作这么多年过来了,回过头来看看,自己积累了什么呢,再看一下5、6年前鄙人的BLOG发现那时还是留下了些东西的,而且写本文时,重温Java的线程同步机制时,看到当时写的东西,发现如果是当时是自己理解的东西,并且用自己擅长的领域表达出来,自己回头再看时,一目了然,几个UML图就能解决问题了。

修正记录

2011/07/18 修改标题、摘要及关键词

消息发送分发处理的主要参与者是Looper, Handler,还有Thread的执行。很多应用场景有他们参与就可完成,HandlerThread倒是WifiService处理时消息处理的一个特例,所以,在这些关键点上去掉HandlerThread。


***************************** 全文结束 *******************************

结束了这位大侠的作品后我给出自己从宏观的角度去理解Handler的消息机制图解:



更多相关文章

  1. android 获取 USB 拔插广播消息
  2. Handler使用总结
  3. Android(安卓)之 Activity的加载模式
  4. 《Android开发从零开始》――18.消息处理详解
  5. android annotation配置及简单使用
  6. Android(安卓)Socket实例(2)
  7. Android(安卓)activity launch mode
  8. android报The content of the adapter has changed but ListView
  9. Android实现内存中数据保存到sdcard的方法

随机推荐

  1. Android知识要点整理(2)----- 应用资源
  2. Android零散知识点积累
  3. SDK大全2的读书笔记
  4. 如何使用SQLiteOpenHelper
  5. Androidz之clickable
  6. android混淆(Obfuscate)
  7. Android(安卓)threading
  8. [Android] 自定义Indeterminate Progress
  9. Android(安卓)自定义View 例子一
  10. 安卓动画研究