谈谈对handler,Looper,Message的android消息处理机制

Android是消息驱动的,实现消息驱动有几个要素:

  1. 消息的表示:Message
  2. 消息队列:MessageQueue
  3. 消息循环,用于循环取出消息进行处理:Looper
  4. 消息处理,消息循环从消息队列中取出消息后要对消息进行处理:Handler


     为一个线程建立消息循环有四个步骤:

     1、  初始化Looper

     2、  绑定handler到CustomThread实例的Looper对象

     3、  定义处理消息的方法

     4、  启动消息循环


     1、  初始化Looper : Looper.prepare()

      Looper.java

[java]   view plain copy
  1. private static final ThreadLocal sThreadLocal = new ThreadLocal();  
  2. public static final void prepare() {  
  3.         if (sThreadLocal.get() != null) {  
  4.             throw new RuntimeException("Only one Looper may be created per thread");  
  5.         }  
  6.         sThreadLocal.set(new Looper());  
  7. }  
       一个线程在调用Looper的静态方法prepare()时,这个线程会新建一个Looper对象,并放入到线程的局部变量中,而这个变量是不和其他线程共享       的(关于ThreadLocal的介绍)。下面我们看看Looper()这个构造函数:
      Looper.java
[java]   view plain copy
  1. final MessageQueue mQueue;  
  2. private Looper() {  
  3.         mQueue = new MessageQueue();  
  4.         mRun = true;  
  5.         mThread = Thread.currentThread();  
  6.     }  
       可以看到在Looper的构造函数中,创建了一个消息队列对象mQueue,此时,调用Looper. prepare()的线程就建立起一个消息循环的对象(此时          还没开始进行消息循环)即:一个线程可以产生一个Looper。
       2、  绑定handler到CustomThread实例的Looper对象 : mHandler= new Handler()
       Handler.java
[java]   view plain copy
  1. final MessageQueue mQueue;  
  2.  final Looper mLooper;  
  3. public Handler() {  
  4.         if (FIND_POTENTIAL_LEAKS) {  
  5.             final Class<? extends Handler> klass = getClass();  
  6.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  7.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  
  8.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  9.                     klass.getCanonicalName());  
  10.             }  
  11.         }  
  12.   
  13.         mLooper = Looper.myLooper();  
  14.         if (mLooper == null) {  
  15.             throw new RuntimeException(  
  16.                 "Can't create handler inside thread that has not called Looper.prepare()");  
  17.         }  
  18.         mQueue = mLooper.mQueue;  
  19.         mCallback = null;  
  20. }  

          Handler通过mLooper = Looper.myLooper();绑定到线程的局部变量Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消           息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。

[java]   view plain copy
  1. public static final void loop() {  
  2.        Looper me = myLooper();  
  3.        MessageQueue queue = me.mQueue;  
  4.          
  5.        // Make sure the identity of this thread is that of the local process,  
  6.        // and keep track of what that identity token actually is.  
  7.        Binder.clearCallingIdentity();  
  8.        final long ident = Binder.clearCallingIdentity();  
  9.          
  10.        while (true) {  
  11.            Message msg = queue.next(); // might block  
  12.            //if (!me.mRun) {  
  13.            //    break;  
  14.            //}  
  15.            if (msg != null) {  
  16.                if (msg.target == null) {  
  17.                    // No target is a magic identifier for the quit message.  
  18.                    return;  
  19.                }  
  20.                if (me.mLogging!= null) me.mLogging.println(  
  21.                        ">>>>> Dispatching to " + msg.target + " "  
  22.                        + msg.callback + ": " + msg.what  
  23.                        );  
  24.                msg.target.dispatchMessage(msg);  
  25.                if (me.mLogging!= null) me.mLogging.println(  
  26.                        "<<<<< Finished to    " + msg.target + " "  
  27.                        + msg.callback);  
  28.                  
  29.                // Make sure that during the course of dispatching the  
  30.                // identity of the thread wasn't corrupted.  
  31.                final long newIdent = Binder.clearCallingIdentity();  
  32.                if (ident != newIdent) {  
  33.                    Log.wtf("Looper""Thread identity changed from 0x"  
  34.                            + Long.toHexString(ident) + " to 0x"  
  35.                            + Long.toHexString(newIdent) + " while dispatching to "  
  36.                            + msg.target.getClass().getName() + " "  
  37.                            + msg.callback + " what=" + msg.what);  
  38.                }  
  39.                  
  40.                msg.recycle();  
  41.            }  
  42.        }  
  43.    }  

3、定义处理消息的方法:Override public void handleMessage (Message msg){} 子类需要覆盖这个方法,实现接受到消息后的处理方法。

4、启动消息循环 : Looper.loop()

      所有准备工作都准备好了,是时候启动消息循环了!Looper的静态方法loop()实现了消息循环。

Looper.java

while(true)体现了消息循环中的“循环“,Looper会在循环体中调用queue.next()获取消息队列中需要处理的下一条消息。当msg != null且msg.target != null时,调用msg.target.dispatchMessage(msg);分发消息,当分发完成后,调用msg.recycle();回收消息。

msg.target是一个handler对象,表示需要处理这个消息的handler对象。Handler的void dispatchMessage(Message msg)方法如下:

Handler.java


[java]   view plain copy
  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.         }  


消息的创建方式
       Message一般创建对象使用 Message m = Message.obtain(); 之所以这样操作时因为系统的消息池可能存在消息未被使用,我们可通过该方法去获取未被使用的消息,这样就能够避免一直新建消息对象而又存在很多未被使用消息存在内存,达到节省内存目的。这是sdk关于Message.obtain函数的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static final Object  sPoolSync  =   new Object();
private static Message  sPool ;
private static int sPoolSize  =  0 ;
private static final int MAX_POOL_SIZE  =  50 ;
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized ( sPoolSync ) {
if ( sPool  !=   null ) {
   Message m =  sPool ;
   sPool  = m. next ;
   m. next  =   null ;
   sPoolSize --;
  return  m;
 }
}
return  new  Message();     
}
   可以看出obtain会先去判断消息池是否为空,如果为空则new Message(),如果不是则从消息池取出消息返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值