Android消息处理机制---紧接上篇

在Android系统中,关于消息的处理几乎随处可见。提到消息处理,很自然就会想到消息的发送,消息的存储以及消息的处理这三个方面。

Android系统的消息机制与thread,looper,handler,messagequeue,message这几个类是分不开的,此外还有一个runnalbe类,其实,它最终也会被封装为message。下面首先介绍这几个类以及他们之间的关系,然后按照消息的发送,消息的存储,以及消息的处理来分析。

一、各个对象的简单介绍

thread:在多线程运行环境里,代码段的执行都是线程相关的,中断处理例程除外,它是工作于中断上下文的。Android基于linux,linux本身支持多线程。而我们的looper,handler,messagequeue,message这些对象都是寄宿在某个线程里面的。搞清楚这一点也有利于我们后面理解handler的处理到底是在哪个线程里完成的。

looper:顾名思义,实现一个循环动作。因为通常我们在实现一个线程时会让它做一个无限循环,在循环中处理各种不同的事务。looper的作用就是实现宿主线程的消息循环,后面的代码分析中会看到这一点。它负责从messagequeue中取出消息,然后根据消息指定的handler或者callback来处理这条消息。

messagequeue:消息队列就是存储消息的地方,它利用链表的方法来管理消息,looper就是从这里来获取消息的。

message:单条的消息。里面包含了消息类型,参数,标志位和处理者等等信息,后面代码分析中会详细讲到。

runnable:被封装成消息后发送到消息队列,最终会调用到它的run()方法。

相关的源文件:

HandlerThread.java(继承自java.lang.thread类)

Looper.java

MessageQueue.java

Message.java

Runnable.java

 

二、代码分析(以Audioservice.java中的AudioHandler为例)

首先看看我们的信使message是如何定义的:

 

[java] view plaincopy
 
  1. public final class Message implements Parcelable {  
  2.     /** 
  3.      * User-defined message code so that the recipient can identify  
  4.      * what this message is about. Each {@link Handler} has its own name-space 
  5.      * for message codes, so you do not need to worry about yours conflicting 
  6.      * with other handlers. 
  7.      */  
  8.     public int what;  
  9.   
  10.     public int arg1;   
  11.   
  12.     public int arg2;  
  13.   
  14.     public Object obj;  
  15.   
  16.     /** 
  17.      * Optional Messenger where replies to this message can be sent.  The 
  18.      * semantics of exactly how this is used are up to the sender and 
  19.      * receiver. 
  20.      */  
  21.     public Messenger replyTo;  
  22.   
  23.     /*package*/ int flags;  
  24.   
  25.     /*package*/ long when;  
  26.       
  27.     /*package*/ Bundle data;  
  28.       
  29.     /*package*/ Handler target;       
  30.       
  31.     /*package*/ Runnable callback;     
  32.       
  33.     // sometimes we store linked lists of these things  
  34.     /*package*/ Message next;  

比较重要的几个变量都标识出来了,what用来对消息进行分类,通常在handler中处理时会使用switch(what) case what:来处理.arg1和arg2就是消息里的参数,作什么用可以自行定义。flags用来指出消息是否在使用中,是否为异步消息。when用来指明消息何时被处理,这样就使消息的处理更加灵活了。handler就是消息的处理者。callback是消息处理的另一种方式,当消息中指定了callback,则直接调用callback的run()方法来处理消息,不会再交给handler处理。等分析到后面这一点就会很清晰了。

 

 

再来看看thread是如何创建的:

在AudioService的构造函数中(AudioService是在System Server中实例化的,可以参考Android启动流程),调用

[java] view plaincopy
 
  1. public AudioService(Context context) {  
  2.     mContext = context;  
  3.     ……  
  4.     createAudioSystemThread();  
  5.     ……  

 

 

 

[java] view plaincopy
 
  1. private void createAudioSystemThread() {  
  2.     mAudioSystemThread = new AudioSystemThread();  
  3.     mAudioSystemThread.start();  
  4.     waitForAudioHandlerCreation();  
  5. }  


首先创建一个AudioSystemThread,继承自Thread类(handlerthread也是继承这个类,可以认为AudioSystemThread只是给handlerthread另取了个名字),在调用start之后就会进入它的run()方法,通常,run()里面都会有一个无限循环,我们平时创建线程的时候大多数都是这么使用的,在线程里面做无限循环来处理事情。

 

 

[java] view plaincopy
 
  1. /** Thread that handles native AudioSystem control. */  
  2. private class AudioSystemThread extends Thread {  
  3.     AudioSystemThread() {  
  4.         super("AudioService");  
  5.     }  
  6.   
  7.     @Override  
  8.     public void run() {  
  9.         // Set this thread up so the handler will work on it  
  10.         Looper.prepare();<strong>  
  11. rong>  
  12.         synchronized(AudioService.this) {  
  13.             mAudioHandler = new AudioHandler();  
  14.   
  15.             // Notify that the handler has been created  
  16.             AudioService.this.notify();  
  17.         }  
  18.   
  19.         // Listen for volume change requests that are set by VolumePanel  
  20.         Looper.loop();  
  21.     }  
  22. }  


在这个里面,thread已经创建好了,几大角色同时登场,looper出现了,handler也有了,还有message和messagequeue不见踪影。接着看:

 

 

[java] view plaincopy
 
  1. public static void prepare() {  
  2.     prepare(true);  
  3. }  
  4.   
  5. private static void prepare(boolean quitAllowed) {  
  6.     if (sThreadLocal.get() != null) {  
  7.         throw new RuntimeException("Only one Looper may be created per thread");  
  8.     }  
  9.     sThreadLocal.set(new Looper(quitAllowed));  
  10. }  

在prepare的时候new了一个looper对象了,看看looper的构造函数:

 

 

[java] view plaincopy
 
  1. private Looper(boolean quitAllowed) {  
  2.     mQueue = new MessageQueue(quitAllowed);  
  3.     mRun = true;  
  4.     mThread = Thread.currentThread();  
  5. }  

 

到现在为止,另一个重要角色MessageQueue也出现了,最后在run()函数中调用Looper.loop()开始消息循环:

 

[java] view plaincopy
 
  1. public static void loop() {  
  2.     final Looper me = myLooper();  
  3.     if (me == null) {  
  4.         throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
  5.     }  
  6.     final MessageQueue queue = me.mQueue;  
  7.   
  8.     // Make sure the identity of this thread is that of the local process,  
  9.     // and keep track of what that identity token actually is.  
  10.     Binder.clearCallingIdentity();  
  11.     final long ident = Binder.clearCallingIdentity();  
  12.   
  13.     for (;;) {  
  14.         Message msg = queue.next();<strong> </strong>// might block  
  15.         if (msg == null) {  
  16.             // No message indicates that the message queue is quitting.  
  17.             return;  
  18.         }  
  19.   
  20.         // This must be in a local variable, in case a UI event sets the logger  
  21.         Printer logging = me.mLogging;  
  22.         if (logging != null) {  
  23.             logging.println(">>>>> Dispatching to " + msg.target + " " +  
  24.                     msg.callback + ": " + msg.what);  
  25.         }  
  26.   
  27.         msg.target.dispatchMessage(msg);  
  28.   
  29.         if (logging != null) {  
  30.             logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
  31.         }  
  32.   
  33.         // Make sure that during the course of dispatching the  
  34.         // identity of the thread wasn't corrupted.  
  35.         final long newIdent = Binder.clearCallingIdentity();  
  36.         if (ident != newIdent) {  
  37.             Log.wtf(TAG, "Thread identity changed from 0x"  
  38.                     + Long.toHexString(ident) + " to 0x"  
  39.                     + Long.toHexString(newIdent) + " while dispatching to "  
  40.                     + msg.target.getClass().getName() + " "  
  41.                     + msg.callback + " what=" + msg.what);  
  42.         }  
  43.   
  44.         msg.recycle();  
  45.     }  
  46. }  


这里面有一个for无限循环,上面也提过,一般我们创建一个线程的时候会利用无限循环来处理事务,这个无限循环就是在AudioSystemThread的run()函数中。looper的循环也不复杂,它要做的事情就是从messagequeue中取出消息,然后调用消息指定的target的dispatchMessage()函数。

 

还记得上面说过这个target其实就是一个handler,自然dispatchMessage()就是在handler中定义的:

 

[java] view plaincopy
 
  1. public void dispatchMessage(Message msg) {  
  2.     if (msg.callback != null) {  
  3.         handleCallback(msg);  
  4.     } else {  
  5.         if (mCallback != null) {  
  6.             if (mCallback.handleMessage(msg)) {  
  7.                 return;  
  8.             }  
  9.         }  
  10.         handleMessage(msg);  
  11.     }  
  12. }  

从上面可以看出,主要有三个执行分支,如果定义了callback,那么就调用handleCallback()来处理消息,handleMessage不会执行,这个callback其实是一个Runnable实例,它是一个接口类,在使用它的时候,最终会调用它的run()函数;如果没有定义callback,那么就会走到else分支,如果定义了mCallback,就会调用它的handleMessage()来处理,mCallback是什么呢?从它的成员函数也大概能猜到也是一个handler,怎么来的?在后面handler的构造函数中就会看到;如果没有定义mCallback或者handleMessage()返回值为0,则调用targe,即当前实例handler的handleMessage()。

 

handler的构造函数有4个:

 

[java] view plaincopy
 
  1. public Handler(){  
  2. ……  
  3. mLooper = Looper.myLooper();  
  4. ……  
  5. mQueue = mLooper.mQueue;  
  6. mCallback = null;  
  7. }  
  8.   
  9. public Handler(Callback callback){  
  10. ……  
  11. mLooper = Looper.myLooper();  
  12. ……  
  13. mQueue = mLooper.mQueue;  
  14. mCallback = callback;  
  15. }  
  16.   
  17. public Handler(Looper looper) {  
  18.         mLooper = looper;  
  19.         mQueue = looper.mQueue;  
  20.         mCallback = null;  
  21. }  
  22.   
  23. public Handler(Looper looper, Callback callback) {  
  24.         mLooper = looper;  
  25.         mQueue = looper.mQueue;  
  26.         mCallback = callback;  
  27. }  


在创建handler时,如果没有指定looper,那么这个looper就是当前线程的looper,之后looper取出消息并调用handler的handleMessage()方法来处理消息时,都是运行在looper所在的线程上下文中。如果指令了looper,则消息的处理会在指定的looper所在线程上下文中进行。所以,looper是线程相关的,looper决定了消息在哪个线程里处理。

 

在实现一个handler时,handleMessage是需要用户根据自己的需要重写的一个函数,例如上面的AudioHandler:

 

[java] view plaincopy
 
  1. @Override  
  2. public void handleMessage(Message msg) {  
  3.   
  4.     switch (msg.what) {  
  5.   
  6.         case MSG_SET_DEVICE_VOLUME:  
  7.             setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);  
  8.             break;  
  9.   
  10.         case MSG_SET_ALL_VOLUMES:  
  11.             setAllVolumes((VolumeStreamState) msg.obj);  
  12.             break;  
  13.   
  14.         case MSG_PERSIST_VOLUME:  
  15.             persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);  
  16.             break;  



 

至此,各个对象基本介绍完了。而且关于消息的处理上面也有说过,looper通过queue.next获取消息,然后调用handler的dispatchMessage()来处理消息,但是消息从何而来呢?下面就来说说消息的发送:

    当我们需要handler来完成某件事情时,首先当然是要往消息队列里发送消息,看看AudioHandler的实现:

 

[java] view plaincopy
 
  1. // Post message to set system volume (it in turn will post a message  
  2. // to persist).  
  3. sendMsg(mAudioHandler,  
  4.         MSG_SET_DEVICE_VOLUME,  
  5.         SENDMSG_QUEUE,  
  6.         device,  
  7.         0,  
  8.         streamState,  
  9.         0);  

这种方式是直接发送消息,事先并不构建消息实例,消息实例的构造放在这种类型的sendMsg()函数中(sendMsg也有很多个重载同名函数):

 

 

[java] view plaincopy
 
  1. private static void sendMsg(Handler handler, int msg,  
  2.         int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {  
  3.   
  4.     if (existingMsgPolicy == SENDMSG_REPLACE) {  
  5.         handler.removeMessages(msg);  
  6.     } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {  
  7.         return;  
  8.     }  
  9.   
  10.     handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);  
  11. }  


创建message的接口就是这个obtainMessage():

 

 

[java] view plaincopy
 
  1. public final Message obtainMessage(int what, int arg1, int arg2, Object obj)  
  2. {  
  3.     return Message.obtain(this, what, arg1, arg2, obj);  
  4. }  

 

紧接着看Message类的obtain:

 

[java] view plaincopy
 
  1.     public static Message obtain(Handler h, int what,  
  2.             int arg1, int arg2, Object obj) {  
  3.         Message m = obtain();  
  4.         m.target = h;  
  5.         m.what = what;  
  6.         m.arg1 = arg1;  
  7.         m.arg2 = arg2;  
  8.         m.obj = obj;  
  9.   
  10.         return m;  
  11.     }  
  12.    
  13. public static Message obtain() {  
  14.         synchronized (sPoolSync) {  
  15.             if (sPool != null) {  
  16.                 Message m = sPool;  
  17.                 sPool = m.next;  
  18.                 m.next = null;  
  19.                 sPoolSize--;  
  20.                 return m;  
  21.             }  
  22.         }  
  23.         return new Message();  
  24.     }  

消息的target就是传递进来的handler。
前面都是在说消息是如何创建出来的,现在接着发送消息的地方来分析:

 

 

[java] view plaincopy
 
  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  2. {  
  3.     boolean sent = false;  
  4.     MessageQueue queue = mQueue;  
  5.     if (queue != null) {  
  6.         msg.target = this;  
  7.         sent = queue.enqueueMessage(msg, uptimeMillis);  
  8.     }  
  9.     else {  
  10.         RuntimeException e = new RuntimeException(  
  11.             this + " sendMessageAtTime() called with no mQueue");  
  12.         Log.w("Looper", e.getMessage(), e);  
  13.     }  
  14.     return sent;  
  15. }  

直接往队列里提交一条消息。接下来looper就会取出该消息并处理。

 

////////////////////////////

还有runnable没有说到,通常,runnable是这样使用的:

 

[java] view plaincopy
 
  1. handler.post(new Runnable() {  
  2.        public void run() {  
  3.            mCallback.run(Future2Task.this);  
  4.        }  
  5. });  

调用handler的post接口,在里面实例化一个runnable对象,重写它的run()函数。

 

 

[java] view plaincopy
 
  1. public final boolean post(Runnable r)  
  2. {  
  3.    return  sendMessageDelayed(getPostMessage(r), 0);  
  4. }  
[java] view plaincopy
 
  1. private static Message getPostMessage(Runnable r) {  
  2.     Message m = Message.obtain();  
  3.     m.callback = r;  
  4.     return m;  
  5. }  

将message的callback赋值为r,这样,在前面的dispatchMessage()中,就会调用handlecallback(m)了:

 

 

[java] view plaincopy
 
  1. private static void handleCallback(Message message) {  
  2.     message.callback.run();  
  3. }  

非常简单,直接调用run()函数。

 

 

三、总结

1.looper是线程相关的,一个线程最多只能创建一个looper,前面的分析中没有说,仔细研究looper的创建就会发现这一点。

2.handler的消息发往哪个looper,消息就会在looper的那个线程中得到处理。在构造handler的时候,如果没有指定looper,那么默认就是在创建handler对象的 线程中处理,如果指定了另外一个线程的looper,那么消息就在另外一个looper所在线程中处理。

3.looper从messagequeue中获取消息时,如果没有消息会睡眠等待,这是通过native层的进程通信FIFO实现的。

posted @ 2014-12-18 23:40  MMLoveMeMM  阅读(322)  评论(0)    收藏  举报