【Android】Handler、Looper源碼分析

1、前言html

  源碼分析使用的版本是 4.4.2_r1。android

  Handler和Looper的入門知識以及講解能夠參考個人另一篇博客:Android Handler機制程序員

  簡單而言:Handler和Looper是對某一個線程實現消息機制的重要組成部分,另外兩個重要元素是Message和MessageQueue,經過這四個類,可讓某個線程具有接收、處理消息的能力。app

 

2、源碼剖析less

  雖然只有四個類,並且這裏只是剖析其中兩個,可是也不能獨立分析,必須組合進行解析。切入點是類Looper的註釋中的一段示例代碼:async

 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入手,看看這裏到底作了什麼。ide

代碼一:函數

 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行調用。oop

  第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機制

 

3、總結

  源碼剖析中,主要關注的對象是:Thread,Handler,Looper三個重量級對象是如何綁定到一塊兒的,以及消息是如何在Handler和Looper中存在和傳播的,從源碼中看這個過程很是清楚。其實整個設計並無什麼新奇的技巧,可是設計很是合理,值得借鑑。

  下一篇博客會去探索一下MessageQueue,關於MessageQueue如何管理消息,和Looper一塊兒實現延遲消息,我很是感興趣。

相關文章
相關標籤/搜索