FROM:http://blog.sina.com.cn/s/blog_49f62c350101gts9.html


正如其他GUI应用程序一样,Android应用程序也是消息(事件)驱动的。这种消息的传递必须依赖于应用框架提供的消息机制。Android本身提供了2种消息机制:

 ·        组件间消息传递 --- Intent

 ·        线程间消息传递 --- Message

  本文主要讨论Android线程间消息传递机制及其应用。


1.Android Message机制

所谓消息机制,就是实现消息传递、消息分发、消息处理的一套程序逻辑,一般属于应用程序框架的功能范围。应用程序开发者可以利用应用程序框架提供的消息API来开发应用。典型的消息APISendMessage(), PostMessage(), HandleMessage(),DispatchMessage(). 同理,Android Message机制也提供了类似API,其内部实现机制也跟其他平台一样,基于消息队列。但是Android Message都是异步处理的。

1.1 消息传递

Android Message机制的消息队列采用单链表结构。

Android Message机制及其应用_第1张图片

其中mMessages是头指针,m1, m2, m3..Message节点。每个Android消息都有个相对开机时间的过期时间,消息队列是基于这个过期时间先后顺序排序的,需要尽快处理的消息排在前面。所以其插入算法是:

Android Message机制及其应用_第2张图片

参考代码:\frameworks\base\core\java\android\os\MessageQueue.java@enqueueMessage()

1.2 消息分发

Android 设计了一个死循环来负责消息的分发, 它不停的从消息队列获取过期的消息,一旦取得,就调用该message对应的handler去处理。由于消息队列是基于消息过期时间排序的。所以该分发函数的实现逻辑非常简单,每次只是判断第1个节点对应的消息是否过期,如果过期,则从链表取走(删除),并分发给该消息对应的handler去处理,处理之后回收该消息结构;如果没有过期的消息,则block自己一段时间(可能消息队列里没有消息了) 主要实现逻辑如下:

Android Message机制及其应用_第3张图片

参考代码:\frameworks\base\core\java\android\os\Looper.java@loop()

         \frameworks\base\core\java\android\os\MessageQueue.java@next()

其中msg.target是预先设置的消息处理handler。每个消息都一个对应的handler,handler负责分发或默认处理消息。msg.recycle()负责把用完的消息结构回收,以便复用该结构。

1.3 消息处理

跟其他平台的消息机制一样,Android也提供了接口供用户注册/创建自己的消息处理方法,同时也支持消息携带特定的处理函数,因此Android的消息处理更加灵活。

基本逻辑如下:

Android Message机制及其应用_第4张图片
   参考代码:\frameworks\base\core\java\android\os\Handler.java@dispatchMessage()

 

2. Message相关的类

Android Message机制中用到以下几个重要类:

Looper,  MessageQueue, Message, Handler

它们之间的关系是

Android Message机制及其应用_第5张图片

2.1 Message

该类负责Message对象的创建/回收/销毁,对应一个特定的消息。维护一个可用消息链表用于回收用完的消息结构(最大size10)。

参考代码:frameworks\base\core\java\android\os\Message.java

2.2 MessageQueue

该类实现Message队列,它是个单链表结构,提供链表的插入/删除/检索操作。外部可以利用特定函数对消息进行链表操作。它总是被Looper创建,与Looper是一对一的关系。

参考代码:\frameworks\base\core\java\android\os\MessageQueue.java

2.3 Looper

该类实现消息的定时分发,属于消息机制的核心机构。它负责轮询消息队列,找出过期的消息并分发特定handler进行处理。因此一个Looper必须有一个MessageQueue

参考代码:\frameworks\base\core\java\android\os\Looper.java 

2.4 Handler

该类实现消息的发送以及处理,负责发送用户消息以及调用用户注册的callback或接口进行消息处理。因此每个消息肯定有一个对应的handler,否则消息无法被发送/处理。

参考代码:\frameworks\base\core\java\android\os\Handler.java

2.5 ThreadLocal

该类存储Thread相关的数据。此处用于存储与Thread关联的Looper实例。这样每个Thread都可以有自己的消息队列以及消息处理方式。

2.6 Callback

该类是一个接口,用户在创建Handler实例时可以传入该interface实例,这样一旦消息到来,handler会调用该接口来处理。

2.7 Runnable

该类也是一个接口,用户可以向特定的Runnable发送消息,一旦成功,该Runnable会被调用。一旦某个消息指定了自己的callback(Runnable), 那么该消息将交给它的callback去处理,不会交给HandlerCallback接口或HandlerhandleMessage()处理。

在实际应用中,它们有如下的调用关系:

Android Message机制及其应用_第6张图片

3. Thread的关系

·        1Android 应用程序默认只有1Process,但可以有多个Thread

·        1Android 应用程序对应1ActivityThread实例, 它就是应用的主线程(UI 线程)

·        系统默认为主线程创建了1个消息循环(Looper),并启动它开始接收消息

·        其他线程默认没有Looper,所以没有 MessageQueue,不能接收Message, 如果需要接收Message, 则需要通过Looper.prepare()创建一个MessageQueue

·        1个线程只能有1Looper, 也就是说只能有1MessageQueue

·        1个线程可以有多个Handler, 多个Runnable,  多个Callback


4. Message
机制的应用

4.1 子线程向主线程发送消息

主线程中所做的操作最好耗时非常短,一般建议创建子线程去完成比较费时的工作(访问网络,下载数据,查询数据库等), 以免主线程阻塞而发生ANR异常。但子线程通常不能更新UI,异常android.view.ViewRoot$CalledFromWrongThreadException:Onlythe original thread that created a view hierarchy can touch itsviews。所以子线程与主线程需要通过Message来沟通信息。这个场景很常见。实现逻辑如下:

  主线程创建Handler实例
   privateHandler mHandler = new Handler(new Handler.Callback() {

public boolean handleMessage(Message msg){

        switch (msg.what) {
       case UPDATE_UI:

       {
              //updateUI

              break;
       }
     default:
     break;
}});

                 
  子线程利用主线程的
Handler
向主线程发送消息:
   MessagenotifyMsg = mHandler.obtainMessage(UPDATE_UI, 60, 100, null);
   mHandler.sendMessage(notifyMsg) ;


4.2 主线程向子线程发送消息

  子线程创建自己的
Handler
实例并建立消息Looper

class subThread extends Thread{

   public void run() {

Looper.prepare();

mSubThreadHandler= new Handler(){

        public void handleMessage(Message msg) {

              Log.e(sTag, (String)msg.obj);

                       }

             };

         Looper.loop();

 }

}


  主线程利用子线程的
Handler
向子线程发送消息:

Message cmdMsg =mSubThreadHandler.obtainMessage(CMD_STOP, 0, 0, null);mSubThreadHandler.sendMessage(cmdMsg);


4.3 Runnable发送消息

可以通过Handler直接发送消息来运行某个Runnable。这种方式更像用消息机制实现一个Timer来完成某个工作。Runnable运行在Handler所在的线程中,单次执行。

mHandler.post(new Runnable(){

   public void run() {

          //do something

  }

});

 

由于ThreadRunnable的子类,也可以这样使用:

Thread myThread = new Thread(){

           public void run() {

                  //do something              

           }

};

mHandler.post(myThread);

注意此时并不会启动一个线程,跟上面的runnable方式一样,run()会运行在Handler所在的线程中,本质上就等同于Handler调用myThread.run(), 就是一个普通调用,所以不会新开一个线程。