android Handler Looper,MessageQueue消息机制原理

安卓消息处理类:

Looper、Handler、MessageQueue、Message、ThreadLocal、ThreadLocal.Values、HandlerThread。

Looper:

线程默认是没有消息循环的,要为一个线程创建一个消息循环通过调用prepare(),然后在调用loop()方法进入消息循环(这意味着线程将一直在此方法循环)。例如:
[java] view plain copy
 
 print?
  1. class LooperThread extends Thread {  
  2.       public Handler mHandler;  
  3.   
  4.       public void run() {  
  5.           Looper.prepare();  
  6.   
  7.           mHandler = new Handler() {  
  8.               public void handleMessage(Message msg) {  
  9.                   // process incoming messages here  
  10.               }  
  11.           };  
  12.   
  13.           Looper.loop();  
  14.       }  
  15.   }  
那么到这里你肯定会想安卓的主线程并没有prepare和loop也可以创建Handler,处理消息循环。这是因为安卓在创建主线程的时候已经为我们添加了消息循环。

那么Looper如何管理每一个线程对应的一个looper的呢?
[java] view plain copy
 
 print?
  1. public final class Looper {  
  2.     // sThreadLocal.get() will return null unless you've called prepare().  
  3.     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();  
  4.     private static Looper sMainLooper;  // guarded by Looper.class  
  5.   
  6.     final MessageQueue mQueue;  
  7.     final Thread mThread;  
  8.   
  9.     private Printer mLogging;  
  10.   
  11.     public static void prepare() {  
  12.         prepare(true);  
  13.     }  
  14.   
  15.     private static void prepare(boolean quitAllowed) {  
  16.         if (sThreadLocal.get() != null) {  
  17.             throw new RuntimeException("Only one Looper may be created per thread");  
  18.         }  
  19.         sThreadLocal.set(new Looper(quitAllowed));  
  20.     }  
  21.   
  22.     public static void prepareMainLooper() {  
  23.         prepare(false);  
  24.         synchronized (Looper.class) {  
  25.             if (sMainLooper != null) {  
  26.                 throw new IllegalStateException("The main Looper has already been prepared.");  
  27.             }  
  28.             sMainLooper = myLooper();  
  29.         }  
  30.     }  
  31.   
  32.     public static Looper getMainLooper() {  
  33.         synchronized (Looper.class) {  
  34.             return sMainLooper;  
  35.         }  
  36.     }  
  37.   
  38.     public static void loop() {  
  39.         final Looper me = myLooper();  
  40.         if (me == null) {  
  41.             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
  42.         }  
  43.         final MessageQueue queue = me.mQueue;  
  44.   
  45.         Binder.clearCallingIdentity();  
  46.         final long ident = Binder.clearCallingIdentity();  
  47.   
  48.         for (;;) {  
  49.             Message msg = queue.next(); // might block  
  50.             if (msg == null) {  
  51.                 // No message indicates that the message queue is quitting.  
  52.                 return;  
  53.             }  
  54.   
  55.             // This must be in a local variable, in case a UI event sets the logger  
  56.             Printer logging = me.mLogging;  
  57.             if (logging != null) {  
  58.                 logging.println(">>>>> Dispatching to " + msg.target + " " +  
  59.                         msg.callback + ": " + msg.what);  
  60.             }  
  61.   
  62.             msg.target.dispatchMessage(msg);  
  63.   
  64.             if (logging != null) {  
  65.                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
  66.             }  
  67.   
  68.             final long newIdent = Binder.clearCallingIdentity();  
  69.             if (ident != newIdent) {  
  70.                 Log.wtf(TAG, "Thread identity changed from 0x"  
  71.                         + Long.toHexString(ident) + " to 0x"  
  72.                         + Long.toHexString(newIdent) + " while dispatching to "  
  73.                         + msg.target.getClass().getName() + " "  
  74.                         + msg.callback + " what=" + msg.what);  
  75.             }  
  76.   
  77.             msg.recycle();  
  78.         }  
  79.     }  
  80.   
  81.     public static Looper myLooper() {  
  82.         return sThreadLocal.get();  
  83.     }  
下面通过图解讲解上面的过程:(prepare调用threadLocal的get的set方法)

Handler类:

构造函数:
1)Handler handler = new Handler(),内部会调用 public Handler(Callback callback, boolean async)方法,将Handler的成员变量mLooper和mQueue赋值为当前线程的looper对象和对应的消息队列,如果当前线程没有looper会抛出异常。
2)Handler handle = new Handler(Looper looper),内部会调用public Handler(Looper looper, Callback callback, boolean async),将参数的looper对象传递给handler的mHandler对象,mQueue对象赋值。通过此方法可以在其它线程中为主线程创建Handler,例如:new Handler(Looper.getMainLooper());
 
handler的sendMessage()方法,在内部会将handler对象赋值为Message的mTarget中,然后调用mQueue将消息发送到线程的消息队列中。

Message类:

Message类内部会保存一个Handler对象mTarget。
 
Looper的loop方法,取出消息,然后调用Message对象中的handler的dispatchMessage方法,dispatchMessage根据callback是否为空执行handleMessage方法。
 
流程图如下:
HandlerThread是一个可以简单创建一个进行消息处理的线程类。

总结:

1)Thread最多与一个looper建立联系。
2)一个looper有且仅有一个MessageQueue
3)一个handler只能与一个looper关联
4)一个Message只能与一个handler关联
这四个一对一的关系使得消息发送和处理得到正确的相应。
posted @ 2017-04-22 15:14  天涯海角路  阅读(122)  评论(0)    收藏  举报