Handle收不到消息的问题分析

说到Handler,今天遇到一个问题:就是handler 发送了消息,却在handleMessage的地方没有收到消息,甚是奇怪。代码如下:


[java]  view plain  copy
 
  1. //创建一个Thread,使得 handler 在子线程中执行耗时操作,而不是在主线程中执行。  
  2. HandlerThread handlerThread = new HandlerThread("handler_thread");  
  3. handlerThread.start();  
  4. // 创建一个Handler 用前面创建的 handlerThread.getLooper()  
  5. mHandler = new Handler(handlerThread.getLooper());  

以上代码,是多么正常的实例化mHandler;然后通过 mHandler.sendEmptyMessage(0); 发送一个消息出去,这是又多么简单的一次操作。可结果却是多么的出人意料。因为同样的代码,同样的操作,可程序在某些情况下,却收不到了消息?!无奈,只能去分析下源码,看看为什么没有收到消息?!

 

问题根因跟踪分析:

1、当我们调用 sendEmptyMessage()方法的时候,最终会调用到 Handler.enqueueMessage 方法

[java]  view plain  copy
 
  1. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
  2.     msg.target = this;  
  3.     if (mAsynchronous) {  
  4.         msg.setAsynchronous(true);  
  5.     }  
  6.     return queue.enqueueMessage(msg, uptimeMillis);  
  7. }  

2、然后跟踪到 MessageQueue.enqueueMessage方法。

[java]  view plain  copy
 
  1. final boolean enqueueMessage(Message msg, long when) {  
  2.     ........  
  3.     boolean needWake;  
  4.     synchronized (this) {  
  5.         // 此处会判断 是否消息队列已经退出,如果退出返回false。  
  6.         if (mQuiting) {  
  7.             RuntimeException e = new RuntimeException(  
  8.                     msg.target + " sending message to a Handler on a dead thread");  
  9.             Log.w("MessageQueue", e.getMessage(), e);  
  10.             return false;  
  11.         }  
  12.   
  13.         ................  
  14.         }  
  15.     }  
  16.     if (needWake) {  
  17.         nativeWake(mPtr);  
  18.     }  
  19.     return true;  
  20. }  

3、那么mQuitting 什么情况会赋值 true呢?跟踪代码找到如下代码:
[java]  view plain  copy
 
  1. final void quit() {  
  2.     if (!mQuitAllowed) {  
  3.         throw new RuntimeException("Main thread not allowed to quit.");  
  4.     }  
  5.   
  6.     synchronized (this) {  
  7.         if (mQuiting) {  
  8.             return;  
  9.         }  
  10.         mQuiting = true;  
  11.     }  
  12.     nativeWake(mPtr);  
  13. }  

由此可见,当调用 quit的时候会对mQuiting进行赋值true,这样在以后的发送消息的时候,就不会添加到消息队列当中去了。

而官方的sendEmptyMessage定义也证明了这一点。

[java]  view plain  copy
 
  1. /** 
  2.  * Sends a Message containing only the what value. 
  3.  *   
  4.  * @return Returns true if the message was successfully placed in to the  
  5.  *         message queue.  Returns false on failure, usually because the 
  6.  *         looper processing the message queue is exiting. 
  7.          (通常情况下不会返回false,除非消息队列被强制退出了) 
  8.  */  
  9. public final boolean sendEmptyMessage(int what)  
  10. {  
  11.     return sendEmptyMessageDelayed(what, 0);  

总结:

通过上面分析,问题的原因就有可能是不合法的调用了 quit方法,搜索项目,发现有些地方,在某些情况下会不和业务逻辑的去执行 quit方法,导致无法处理的消息。再就是可能的一个原因,就是 HandlerThread可能会系统强制回收了。

 

所以,为了安全,我们在调用 发送消息的时候最好做一个判断,如果消息发送不成功则重新创建handler。代码如下:

[java]  view plain  copy
 
  1. private void createHandler(){  
  2.     HandlerThread handlerThread = new HandlerThread("handler_thread");  
  3.     handlerThread.start();  
  4.     mHandler = new Handler(handlerThread.getLooper());  
  5. }  
  6.   
  7. private void sendMessage(int what){  
  8.     boolean isOk = mHandler.sendEmptyMessage(what);  
  9.     if (!isOk){  
  10.         //创建创建handler  
  11.         createHandler();  
  12.         isOk = mHandler.sendEmptyMessage(what);  
  13.     }  
  14. }  

原文地址:http://blog.csdn.net/ilygjl/article/details/51137346


你可能感兴趣的:(android)