理解Handler、Looper、MessageQueue、Thread关系

理解概念:

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

简单关系:


Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。

消息循环过程:

生成消息

[java]  view plain copy print ?
  1. Message message = handler.obtainMessage();  
  2. message.arg1 = id;  
  3. message.obj = drawable;  
  4. handler.sendMessage(message);  

发送消息

[java]  view plain copy print ?
  1. /** 
  2.  * Enqueue a message into the message queue after all pending messages 
  3.  * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 
  4.  * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  5.  * You will receive it in {@link #handleMessage}, in the thread attached 
  6.  * to this handler. 
  7.  *  
  8.  * @param uptimeMillis The absolute time at which the message should be 
  9.  *         delivered, using the 
  10.  *         {@link android.os.SystemClock#uptimeMillis} time-base. 
  11.  *          
  12.  * @return Returns true if the message was successfully placed in to the  
  13.  *         message queue.  Returns false on failure, usually because the 
  14.  *         looper processing the message queue is exiting.  Note that a 
  15.  *         result of true does not mean the message will be processed -- if 
  16.  *         the looper is quit before the delivery time of the message 
  17.  *         occurs then the message will be dropped. 
  18.  */  
  19. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  20. {  
  21.     boolean sent = false;  
  22.     MessageQueue queue = mQueue;  
  23.     if (queue != null) {  
  24.         msg.target = this;  
  25.         sent = queue.enqueueMessage(msg, uptimeMillis);  
  26.     }  
  27.     else {  
  28.         RuntimeException e = new RuntimeException(  
  29.             this + " sendMessageAtTime() called with no mQueue");  
  30.         Log.w("Looper", e.getMessage(), e);  
  31.     }  
  32.     return sent;  
  33. }  

在Handler.java的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。

Looper从消息队列中抽取消息

[java]  view plain copy print ?
  1. /** 
  2.  *  Run the message queue in this thread. Be sure to call 
  3.  * {@link #quit()} to end the loop. 
  4.  */  
  5. public static final void loop() {  
  6.     Looper me = myLooper();  
  7.     MessageQueue queue = me.mQueue;  
  8.     while (true) {  
  9.         Message msg = queue.next(); // might block  
  10.         //if (!me.mRun) {  
  11.         //    break;  
  12.         //}  
  13.         if (msg != null) {  
  14.             if (msg.target == null) {  
  15.                 // No target is a magic identifier for the quit message.  
  16.                 return;  
  17.             }  
  18.             if (me.mLogging!= null) me.mLogging.println(  
  19.                     ">>>>> Dispatching to " + msg.target + " "  
  20.                     + msg.callback + ": " + msg.what  
  21.                     );  
  22.             msg.target.dispatchMessage(msg);  
  23.             if (me.mLogging!= null) me.mLogging.println(  
  24.                     "<<<<< Finished to    " + msg.target + " "  
  25.                     + msg.callback);  
  26.             msg.recycle();  
  27.         }  
  28.     }  
  29. }  

Looper.javaloop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。

处理

[java]  view plain copy print ?
  1. /** 
  2.  * Handle system messages here. 
  3.  */  
  4. public void dispatchMessage(Message msg) {  
  5.     if (msg.callback != null) {  
  6.         handleCallback(msg);  
  7.     } else {  
  8.         if (mCallback != null) {  
  9.             if (mCallback.handleMessage(msg)) {  
  10.                 return;  
  11.             }  
  12.         }  
  13.         handleMessage(msg);  
  14.     }  
  15. }  
在Handler.java的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要实现handleMessage(Message msg)的原因。
至于dispatchMessage方法中的另外一个分支,我将会在后面的内容中说明。
至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。

Handler所处的线程及更新UI的方式

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:

[java]  view plain copy print ?
  1. class LooperThread extends Thread {  
  2.       public Handler mHandler;  
  3.       public void run() {  
  4.             Looper.prepare();  
  5.             mHandler = new Handler() {  
  6.                public void handleMessage(Message msg) {  
  7.                // process incoming messages here  
  8.                }  
  9.             };  
  10.             Looper.loop();  
  11.       }  
  12. }  

在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。
因此,Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。

如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程:
·Activity.runOnUiThread(Runnable)
·View.post(Runnable)
·View.postDelayed(Runnable, long)
·Handler
其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。

总之:

·Handler的处理过程运行在创建Handler的线程里
·一个Looper对应一个MessageQueue
·一个线程对应一个Looper
·一个Looper可以对应多个Handler
·不确定当前线程时,更新UI时尽量调用post方法


原网站:http://blog.csdn.net/richway2010/article/details/6589525

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值