Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android]Handler、Looper源碼分析

[Android]Handler、Looper源碼分析

編輯:關於Android編程

一、前言     源碼分析使用的版本是 4.4.2_r1。     Handler和Looper的入門知識以及講解可以參考我的另外一篇博客:Android Handler機制     簡單而言:Handler和Looper是對某一個線程實現消息機制的重要組成部分,另外兩個重要元素是Message和MessageQueue,通過這四個類,可以讓某個線程具備接收、處理消息的能力。       二、源碼剖析     雖然只有四個類,而且這裡只是剖析其中兩個,但是也不能獨立分析,必須組合進行解析。切入點是類Looper的注釋中的一段示例代碼:   復制代碼  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          Looper.loop(); 13      } 14 } 復制代碼   這段代碼描述了如何將一個普通的線程轉變為一個Looper線程,即讓它具備消息的循環處理能力。我們從Looper入手,看看這裡到底做了什麼。   代碼一:   復制代碼  1 /** Initialize the current thread as a looper.  2       * This gives you a chance to create handlers that then reference  3       * this looper, before actually starting the loop. Be sure to call  4       * {@link #loop()} after calling this method, and end it by calling  5       * {@link #quit()}.  6       */  7     public static void prepare() {  8         prepare(true);  9     } 10  11     private static void prepare(boolean quitAllowed) { 12         if (sThreadLocal.get() != null) { 13             throw new RuntimeException("Only one Looper may be created per thread"); 14         } 15         sThreadLocal.set(new Looper(quitAllowed)); 16     } 復制代碼   這裡展示的是Looper的靜態方法,即prepare(),前面代碼中第5行調用。     第13行可以看到一個運行時異常,其打印信息翻譯為:每一個線程只允許擁有一個Looper,而且判斷條件中用到ThreadLocal對象,如果不明白這是什麼,可以參考我的另外一篇博客:深入理解ThreadLocal。總之,第一次調換用這個方法並且之前沒有調用過,則會調用第15行的代碼,這裡實例化了一個Looper對象,其構造方法如下:   代碼二:   1 private Looper(boolean quitAllowed) { 2      mQueue = new MessageQueue(quitAllowed); 3      mThread = Thread.currentThread(); 4 }   第2行初始化了一個MessageQueue,顧名思義,就是為Looper創建綁定了一個消息隊列。     第3行則獲取當前線程,即調用Looper的線程。這樣即可將Looper綁定到一個線程上,同時為一個線程創建一個消息隊列。     在消息機制裡面,Looper只是負責管理消息隊列,也就是取出消息進行處理,而Handler則是負責發送消息以及處理消息的,那麼Handler和Looper又是如何綁定到一起的呢?看切入點裡面的7-11行,這裡做了什麼呢?下面的分析涉及到Looper中的幾個方法,這裡插入分析一下:   代碼三:   復制代碼  1 /**  2      * Return the Looper object associated with the current thread.  Returns  3      * null if the calling thread is not associated with a Looper.  4      */  5     public static Looper myLooper() {  6         return sThreadLocal.get();  7     }  8   9     /** Returns the application's main looper, which lives in the main thread of the application. 10      */ 11     public static Looper getMainLooper() { 12         synchronized (Looper.class) { 13             return sMainLooper; 14         } 15     } 復制代碼   很明顯可以看到myLooper是獲取屬於當前線程的Looper,而getMainLooper則是獲取應用的主Looper,它由屬性sMainLooper引用,其賦值過程如下。   代碼四:   復制代碼  1     /**  2      * Initialize the current thread as a looper, marking it as an  3      * application's main looper. The main looper for your application  4      * is created by the Android environment, so you should never need  5      * to call this function yourself.  See also: {@link #prepare()}  6      */  7     public static void prepareMainLooper() {  8         prepare(false);  9         synchronized (Looper.class) { 10             if (sMainLooper != null) { 11                 throw new IllegalStateException("The main Looper has already been prepared."); 12             } 13             sMainLooper = myLooper(); 14         } 15     } 復制代碼   注釋中說到,這個方法不應該由程序員自己調用,我猜測這個方法應該是在應用啟動的時候,由屬於應用的第一個線程調用,之後如果再次調用,就會拋出異常了,因為sMainLooper實際上是一個static變量,也就是說它是屬於整個應用的。     准備完畢,現在回到主題,   代碼五:   復制代碼  1     /**  2      * Default constructor associates this handler with the {@link Looper} for the  3      * current thread.  4      *  5      * If this thread does not have a looper, this handler won't be able to receive messages  6      * so an exception is thrown.  7      */  8     public Handler() {  9         this(null, false); 10     } 11     /** 12      * Use the {@link Looper} for the current thread with the specified callback interface 13      * and set whether the handler should be asynchronous. 14      * 15      * Handlers are synchronous by default unless this constructor is used to make 16      * one that is strictly asynchronous. 17      * 18      * Asynchronous messages represent interrupts or events that do not require global ordering 19      * with represent to synchronous messages.  Asynchronous messages are not subject to 20      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 21      * 22      * @param callback The callback interface in which to handle messages, or null. 23      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 24      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 25      * 26      * @hide 27      */ 28     public Handler(Callback callback, boolean async) { 29         if (FIND_POTENTIAL_LEAKS) { 30             final Class<? extends Handler> klass = getClass(); 31             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 32                     (klass.getModifiers() & Modifier.STATIC) == 0) { 33                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 34                     klass.getCanonicalName()); 35             } 36         } 37  38         mLooper = Looper.myLooper(); 39         if (mLooper == null) { 40             throw new RuntimeException( 41                 "Can't create handler inside thread that has not called Looper.prepare()"); 42         } 43         mQueue = mLooper.mQueue; 44         mCallback = callback; 45         mAsynchronous = async; 46     } 復制代碼   重點在於39-43行。第38行調用myLooper()方法獲取屬於本線程的Looper,如果你在這之前沒有調用Looper.prepare()方法,則會返回null,此時就會拋出異常,要求你在這之前調用Looper.prepare()方法。而平時我們在主線程中使用Handler的時候,並不需要調用Looper.prepare()方法,這是因為主線程默認綁定一個Looper。     接下去43行則是獲取Looper的消息隊列。     除了這種簡單的創建方式之外,Handler也還有別的創建方式,比如:   代碼六:   復制代碼  1     /**  2      * Use the provided {@link Looper} instead of the default one and take a callback  3      * interface in which to handle messages.  Also set whether the handler  4      * should be asynchronous.  5      *  6      * Handlers are synchronous by default unless this constructor is used to make  7      * one that is strictly asynchronous.  8      *  9      * Asynchronous messages represent interrupts or events that do not require global ordering 10      * with represent to synchronous messages.  Asynchronous messages are not subject to 11      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 12      * 13      * @param looper The looper, must not be null. 14      * @param callback The callback interface in which to handle messages, or null. 15      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 16      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 17      * 18      * @hide 19      */ 20     public Handler(Looper looper, Callback callback, boolean async) { 21         mLooper = looper; 22         mQueue = looper.mQueue; 23         mCallback = callback; 24         mAsynchronous = async; 25     } 復制代碼   這裡傳入了一個Looper,而mLooper的賦值不是獲取當前線程的Looper,而是直接取用該looper,這引起一個懷疑:一個Looper(或者說一個線程,因為是線程和Looper是一一對應的關系)可以綁定不止一個Handler,因為很明顯我可以用一個Looper通過上述構造方法傳入到不同的Handler中去,那麼自然而然又想到一個問題:Handler是用於發送和處理消息的,那麼當一個Looper綁定多個Handler的時候,發送來的消息肯定都是存儲在Looper的消息隊列中的,那麼處理消息的時候,是怎麼處理的呢?每一個Handler都處理一遍麼?繼續看源碼,首先看發送消息的函數:   代碼七:   復制代碼  1     public final boolean sendMessage(Message msg)  2     {  3         return sendMessageDelayed(msg, 0);  4     }  5   6     public final boolean sendEmptyMessage(int what)  7     {  8         return sendEmptyMessageDelayed(what, 0);  9     } 10  11     public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 12         Message msg = Message.obtain(); 13         msg.what = what; 14         return sendMessageDelayed(msg, delayMillis); 15     } 16  17     public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { 18         Message msg = Message.obtain(); 19         msg.what = what; 20         return sendMessageAtTime(msg, uptimeMillis); 21     } 22  23     public final boolean sendMessageDelayed(Message msg, long delayMillis) 24     { 25         if (delayMillis < 0) { 26             delayMillis = 0; 27         } 28         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 29     } 30  31     /** 32      * Enqueue a message into the message queue after all pending messages 33      * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 34      * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 35      * You will receive it in {@link #handleMessage}, in the thread attached 36      * to this handler. 37      *  38      * @param uptimeMillis The absolute time at which the message should be 39      *         delivered, using the 40      *         {@link android.os.SystemClock#uptimeMillis} time-base. 41      *          42      * @return Returns true if the message was successfully placed in to the  43      *         message queue.  Returns false on failure, usually because the 44      *         looper processing the message queue is exiting.  Note that a 45      *         result of true does not mean the message will be processed -- if 46      *         the looper is quit before the delivery time of the message 47      *         occurs then the message will be dropped. 48      */ 49     public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 50         MessageQueue queue = mQueue; 51         if (queue == null) { 52             RuntimeException e = new RuntimeException( 53                     this + " sendMessageAtTime() called with no mQueue"); 54             Log.w("Looper", e.getMessage(), e); 55             return false; 56         } 57         return enqueueMessage(queue, msg, uptimeMillis); 58     } 復制代碼   為了清晰,前面的方法全部都去掉了注釋,只剩下最後一個方法,我們看到,往消息隊列中添加消息,最後調用的是方法enqueueMessage。其實現如下:   代碼八:   復制代碼 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     } 復制代碼   方法的最後調用了MessageQueue的enqueueMessage方法,從上面的流程可以看到,queue其實就是從mLooper中取出的MessgaeQueue。最終到了這裡,消息可以通過Handler順利壓入綁定的Looper中的MessageQueue中去了。接下去就是消息的處理。這裡需回到Looper中去,因為循環取出消息進行處理是Looper的工作。     前面切入點代碼中可以看到,在調用Looper.prepare()方法,實例化Handler之後,還有一個方法需要調用,即Looper.loop()方法。   代碼九:   復制代碼  1  /**  2      * Run the message queue in this thread. Be sure to call  3      * {@link #quit()} to end the loop.  4      */  5     public static void loop() {  6         final Looper me = myLooper();  7         if (me == null) {  8             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  9         } 10         final MessageQueue queue = me.mQueue; 11  12         // Make sure the identity of this thread is that of the local process, 13         // and keep track of what that identity token actually is. 14         Binder.clearCallingIdentity(); 15         final long ident = Binder.clearCallingIdentity(); 16  17         for (;;) { 18             Message msg = queue.next(); // might block 19             if (msg == null) { 20                 // No message indicates that the message queue is quitting. 21                 return; 22             } 23  24             // This must be in a local variable, in case a UI event sets the logger 25             Printer logging = me.mLogging; 26             if (logging != null) { 27                 logging.println(">>>>> Dispatching to " + msg.target + " " + 28                         msg.callback + ": " + msg.what); 29             } 30  31             msg.target.dispatchMessage(msg); 32  33             if (logging != null) { 34                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 35             } 36  37             // Make sure that during the course of dispatching the 38             // identity of the thread wasn't corrupted. 39             final long newIdent = Binder.clearCallingIdentity(); 40             if (ident != newIdent) { 41                 Log.wtf(TAG, "Thread identity changed from 0x" 42                         + Long.toHexString(ident) + " to 0x" 43                         + Long.toHexString(newIdent) + " while dispatching to " 44                         + msg.target.getClass().getName() + " " 45                         + msg.callback + " what=" + msg.what); 46             } 47  48             msg.recycle(); 49         } 50     } 復制代碼   前面6-16行就不多解釋了,關鍵看17行,這裡是一個死循環,無限循環表示從隊列中獲取消息;第18行也很關鍵,這裡調用MessageQueue的next方法獲取下一個消息,很重要的地方在於注釋:might block。可能會阻塞!如果不注意這一點,很可能就會誤認為調用該方法,因為當時隊列中還沒有消息,所以就會執行第21行,直接返回了,而看到這個注釋,再加上第20-22行的代碼,我們容易猜測,MessageQueue通過在next()方法中返回null來表示整個隊列的取消,從而終結消息機制,OK,不多說,言歸正傳,這一段代碼最重要的是看31行:msg.target.dispatchMessage(msg);這行代碼預示著如何處理消息!     每一個Message都有一個target屬性,該屬性的聲明如下:   1    /*package*/ Handler target;     沒錯,是Handler類型!反觀代碼,在代碼八的第2行,有一行很重要的代碼被忽視了:   1 msg.target = this;   在Handler發送沒一個消息進入隊列之前,都會將其target設置為自己。從這裡就可以看到之前那個問題(紅色部分)的答案,消息是交給發送它的Handler處理的!接下來自然要去看的是Handler的dispatchMessage方法:   復制代碼  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     } 復制代碼   注釋即說明它是處理消息的,在這裡可以進行一些回調,這裡不說明。主要看第13行,調用了handleMessage()方法,其實現如下:   代碼十一:   1 /** 2      * Subclasses must implement this to receive messages. 3      */ 4     public void handleMessage(Message msg) { 5     }   終於到這一步了!注釋中就能看到,我們在實例化Handler的子類的時候,是需要重載這個方法的,否則你的消息不會得到處理,實現參見切入點8-11行!具體使用可以參見我的博客Android Handler機制。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved