Android訊息機制不完全解析(上) .

yangxi_001發表於2016-03-04

Handler和Message是Android開發者常用的兩個API,我一直對於它的內部實現比較好奇,所以用空閒的時間,閱讀了一下他們的原始碼。

   相關的Java Class:
  • android.os.Message
  • android.os.MessageQueue
  • android.os.Looper
  • android.os.Handler
    相關的C++ Class:
  • android.NativeMessageQueue
  • android.Looper
  • android.LooperCallback
  • android.SimpleLooperCallback
  • android.Message
  • android.MessageHandler
首先,來看看這些類之間的關係:


首先,讓我們從相對簡單的java實現開始看起:

Message

    Message類可以說是最簡單的,主要提供了一些成員,用以儲存訊息資料。
  1.  public int what;//用以表示訊息類別   
  2.   
  3.  public int arg1;//訊息資料   
  4.   
  5.  public int arg2;//訊息資料   
  6.   
  7.  public Object obj;//訊息資料   
  8.    
    public int what;//用以表示訊息類別

    public int arg1;//訊息資料

    public int arg2;//訊息資料

    public Object obj;//訊息資料
    
  1. /*package*/ long when;//訊息應該被處理的時間   
  2.   
  3. /*package*/ Bundle data;//訊息資料   
  4.   
  5. /*package*/ Handler target;//處理這個訊息的handler   
  6.   
  7. /*package*/ Runnable callback;//回撥函式   
  8.   
  9. // sometimes we store linked lists of these things   
  10. /*package*/ Message next;//形成連結串列,儲存Message例項  
    /*package*/ long when;//訊息應該被處理的時間
    
    /*package*/ Bundle data;//訊息資料
    
    /*package*/ Handler target;//處理這個訊息的handler
    
    /*package*/ Runnable callback;//回撥函式
    
    // sometimes we store linked lists of these things
    /*package*/ Message next;//形成連結串列,儲存Message例項

    值得一提的是,Android提供了一個簡單,但是有用的訊息池,對於Message這種使用頻繁的型別,可以有效的減少記憶體申請和釋放的次數,提高效能。
  1. private static final Object sPoolSync = new Object();  
  2. private static Message sPool;  
  3. private static int sPoolSize = 0;  
  4.   
  5. private static final int MAX_POOL_SIZE = 50;  
    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;

  1. /** 
  2.  * Return a new Message instance from the global pool. Allows us to 
  3.  * avoid allocating new objects in many cases. 
  4.  */  
  5. public static Message obtain() {  
  6.     synchronized (sPoolSync) {  
  7.         if (sPool != null) {//訊息池不為空,則從訊息池中獲取例項   
  8.             Message m = sPool;  
  9.             sPool = m.next;  
  10.             m.next = null;  
  11.             sPoolSize--;  
  12.             return m;  
  13.         }  
  14.     }  
  15.     return new Message();  
  16. }  
  17.   
  18. /** 
  19.  * Return a Message instance to the global pool.  You MUST NOT touch 
  20.  * the Message after calling this function -- it has effectively been 
  21.  * freed. 
  22.  */  
  23. public void recycle() {  
  24.     clearForRecycle();  
  25.   
  26.     synchronized (sPoolSync) {  
  27.         if (sPoolSize < MAX_POOL_SIZE) {//訊息池大小未滿,則放入訊息池   
  28.             next = sPool;  
  29.             sPool = this;  
  30.             sPoolSize++;  
  31.         }  
  32.     }  
  33. }  
  34. /*package*/ void clearForRecycle() {  
  35.     flags = 0;  
  36.     what = 0;  
  37.     arg1 = 0;  
  38.     arg2 = 0;  
  39.     obj = null;  
  40.     replyTo = null;  
  41.     when = 0;  
  42.     target = null;  
  43.     callback = null;  
  44.     data = null;  
  45. }  
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {//訊息池不為空,則從訊息池中獲取例項
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    /**
     * Return a Message instance to the global pool.  You MUST NOT touch
     * the Message after calling this function -- it has effectively been
     * freed.
     */
    public void recycle() {
        clearForRecycle();

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {//訊息池大小未滿,則放入訊息池
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
    /*package*/ void clearForRecycle() {
        flags = 0;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        when = 0;
        target = null;
        callback = null;
        data = null;
    }

    小結:
  1. Message的核心在於它的資料域,Handler根據這些內容來識別和處理訊息
  2. 應該使用Message.obtain(或者Handler.obtainMessage)函式獲取message例項

Handler

    首先看看建構函式:

  1. public interface Callback {  
  2.     public boolean handleMessage(Message msg);  
  3. }  
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

  1. public Handler() {  
  2.     this(nullfalse);  
  3. }  
    public Handler() {
        this(null, false);
    }
  1. public Handler(Callback callback, boolean async) {  
  2.     if (FIND_POTENTIAL_LEAKS) {  
  3.         final Class<? extends Handler> klass = getClass();  
  4.         if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  5.                 (klass.getModifiers() & Modifier.STATIC) == 0) {  
  6.             Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  7.                 klass.getCanonicalName());  
  8.         }  
  9.     }  
  10.   
  11.     mLooper = Looper.myLooper();  
  12.     if (mLooper == null) {  
  13.         throw new RuntimeException(  
  14.             "Can't create handler inside thread that has not called Looper.prepare()");  
  15.     }  
  16.     mQueue = mLooper.mQueue;  
  17.     mCallback = callback; //使用Callback可以攔截Handler處理訊息,之後會在dispatchMessage函式中,大展身手   
  18.     mAsynchronous = async;//設定handler的訊息為非同步訊息,暫時先無視這個變數   
  19. }  
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback; //使用Callback可以攔截Handler處理訊息,之後會在dispatchMessage函式中,大展身手
        mAsynchronous = async;//設定handler的訊息為非同步訊息,暫時先無視這個變數
    }

    Handler的建構函式最主要的就是初始化成員變數:mLooper和mQueue。 這邊需要注意的一個問題是:Looper.myLooper()不能返回null,否則丟擲RuntimeExeception。稍後詳解Looper.myLooper();函式在何種情況下會丟擲異常。


    Handler.obtainMessage系列的函式都會呼叫Message類中對應的靜態方法,從訊息池中獲取一個可用的訊息例項。典型實現如下:

  1. public final Message obtainMessage()  
  2. {  
  3.     return Message.obtain(this);  
  4. }  
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }


    Handler.post系列和send系列函式最終都會呼叫enqueueMessage函式,把message入列,不同之處在於post系列函式會以Runable引數構建一個Message例項。

  1.  private static Message getPostMessage(Runnable r) {  
  2.     Message m = Message.obtain();  
  3.     m.callback = r;//一會我們會看到callback非空的message和callback為空的mesage在處理時的差異   
  4.     return m;  
  5. }  
  6.   
  7. public final boolean post(Runnable r)  
  8. {  
  9.    return  sendMessageDelayed(getPostMessage(r), 0);  
  10. }  
  11.   
  12. public final boolean sendMessage(Message msg)  
  13. {  
  14.     return sendMessageDelayed(msg, 0);  
  15. }  
  16.   
  17. public final boolean sendMessageDelayed(Message msg, long delayMillis)  
  18. {  
  19.     if (delayMillis < 0) {  
  20.         delayMillis = 0;  
  21.     }  
  22.     return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
  23. }  
  24.   
  25. public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
  26.     MessageQueue queue = mQueue;  
  27.     if (queue == null) {  
  28.         RuntimeException e = new RuntimeException(  
  29.                 this + " sendMessageAtTime() called with no mQueue");  
  30.         Log.w("Looper", e.getMessage(), e);  
  31.         return false;  
  32.     }  
  33.     return enqueueMessage(queue, msg, uptimeMillis);  
  34. }  
  35.   
  36. //最終都會呼叫這個函式,把message入列   
  37. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
  38.     msg.target = this;  
  39.     if (mAsynchronous) {  
  40.         msg.setAsynchronous(true);//Handler的<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">mAsynchronous屬性,決定了msg是否為asynchronous,稍後在MessageQueue.next函式中,可以看到</SPAN><SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">asynchronous對於訊息處理的影響</SPAN><SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">   
  41. AN>        }  
  42.     return queue.enqueueMessage(msg, uptimeMillis);  
  43. }  
     private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;//一會我們會看到callback非空的message和callback為空的mesage在處理時的差異
        return m;
    }

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    //最終都會呼叫這個函式,把message入列
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);//Handler的<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">mAsynchronous屬性,決定了msg是否為asynchronous,稍後在MessageQueue.next函式中,可以看到</span><span style="FONT-FAMILY: Arial, Helvetica, sans-serif">asynchronous對於訊息處理的影響</span><span style="FONT-FAMILY: Arial, Helvetica, sans-serif">
</span>        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    除了這些之外,Handler還提供了hasMessage系列和removeMessages系列函式用以管理Handler對應的MessageQueue中的訊息。


    接下來主角登場,Handler.dispatchMessage:

  1. private static void handleCallback(Message message) {  
  2.     message.callback.run();  
  3. }  
  4. /** 
  5.  * Subclasses must implement this to receive messages. 
  6.  */  
  7. public void handleMessage(Message msg) {  
  8. }  
  9.   
  10. /** 
  11.  * Handle system messages here. 
  12.  */  
  13. public void dispatchMessage(Message msg) {  
  14.     if (msg.callback != null) {//message的callback不為null,則執行   
  15.         handleCallback(msg);  
  16.     } else {  
  17.         if (mCallback != null) {//如果Hanlder的mCallback成員不為null,則呼叫   
  18.             if (mCallback.handleMessage(msg)) {//如果handleMessage返回值為true,則攔截訊息   
  19.                 return;  
  20.             }  
  21.         }  
  22.         handleMessage(msg);//處理訊息   
  23.     }  
  24. }  
    private static void handleCallback(Message message) {
        message.callback.run();
    }
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {//message的callback不為null,則執行
            handleCallback(msg);
        } else {
            if (mCallback != null) {//如果Hanlder的mCallback成員不為null,則呼叫
                if (mCallback.handleMessage(msg)) {//如果handleMessage返回值為true,則攔截訊息
                    return;
                }
            }
            handleMessage(msg);//處理訊息
        }
    }

    註釋應該比較清楚,不多說。 小結:

  1.  Handler類最為核心的函式是enqueueMessage和dispatcherMessage,前者把待處理的訊息放入MessageQueue,而Looper呼叫後者來處理從MessageQueue獲取的訊息。
  2.  callback不為null(通過post系列函式新增到訊息佇列中)的message無法被攔截,而callback為null的函式可以被Handler的mCallback攔截


Looper

    同樣從建構函式看起:
  1. private Looper(boolean quitAllowed) {  
  2.     mQueue = new MessageQueue(quitAllowed);//每個Looper有一個MessageQueue   
  3.     mRun = true;  
  4.     mThread = Thread.currentThread();  
  5. }  
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//每個Looper有一個MessageQueue
        mRun = true;
        mThread = Thread.currentThread();
    }
  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);//後臺執行緒的looper都允許退出   
  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");//每個執行緒只能有一個Looper   
  14.         }  
  15.         sThreadLocal.set(new Looper(quitAllowed));//把例項儲存到TLS(Thread Local Save),僅有每個執行緒訪問自己的Looper   
  16.     }  
  17.   
  18.     /** 
  19.      * Initialize the current thread as a looper, marking it as an 
  20.      * application's main looper. The main looper for your application 
  21.      * is created by the Android environment, so you should never need 
  22.      * to call this function yourself.  See also: {@link #prepare()} 
  23.      */  
  24.     public static void prepareMainLooper() {  
  25.         prepare(false);//主執行緒的lopper不可以退出   
  26.         synchronized (Looper.class) {  
  27.             if (sMainLooper != null) {  
  28.                 throw new IllegalStateException("The main Looper has already been prepared.");  
  29.             }  
  30.             sMainLooper = myLooper();  
  31.         }  
  32.     }  
     ** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);//後臺執行緒的looper都允許退出
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");//每個執行緒只能有一個Looper
        }
        sThreadLocal.set(new Looper(quitAllowed));//把例項儲存到TLS(Thread Local Save),僅有每個執行緒訪問自己的Looper
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);//主執行緒的lopper不可以退出
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    因為是私有的建構函式,所以理論上來說只能通過prepare和prepareMainLooper兩個函式來例項化Looper,但是google的註釋也說的很清楚:prepareMainLooper()應該由系統呼叫(有興趣的同學可以去看看AtivityThread類的main函式),所以,應用開發者可以使用的只剩下prepare函式。
    好了,Looper的例項是構造出來,但是如何獲取構造出來的例項呢?
  1. /** Returns the application's main looper, which lives in the main thread of the application. 
  2.  */  
  3. public static Looper getMainLooper() {  
  4.     synchronized (Looper.class) {  
  5.         return sMainLooper;  
  6.     }  
  7. }  
  8. /** 
  9.  * Return the Looper object associated with the current thread.  Returns 
  10.  * null if the calling thread is not associated with a Looper. 
  11.  */  
  12. public static Looper myLooper() {  
  13.     return sThreadLocal.get();  
  14. }  
    /** Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }
    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }
     現在,我們應該知道如何防止Handler例項化的時候,丟擲RuntimeException:在守護執行緒中例項化Handler之前,需要先呼叫Looper.perpare函式來構造Looper例項。

     然後,重頭戲來了: 
  1.     /** 
  2.      * Quits the looper. 
  3.      * 
  4.      * Causes the {@link #loop} method to terminate as soon as possible. 
  5.      */  
  6.     public void quit() {  
  7.         mQueue.quit();  
  8.     }  
  9.   
  10.     /** 
  11.      * Run the message queue in this thread. Be sure to call 
  12.      * {@link #quit()} to end the loop. 
  13.      */  
  14.     public static void loop() {  
  15.         final Looper me = myLooper();  
  16.         if (me == null) {//呼叫looper之前,需要先呼叫perpare,否則您懂的...   
  17.             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
  18.         }  
  19.         final MessageQueue queue = me.mQueue;  
  20.   
  21.         // Make sure the identity of this thread is that of the local process,   
  22.         // and keep track of what that identity token actually is.   
  23.         Binder.clearCallingIdentity();//不太明白這個函式,但不是重點可以無視   
  24.         final long ident = Binder.clearCallingIdentity();  
  25.   
  26.         for (;;) {  
  27.             Message msg = queue.next(); // might block 獲取一個下一個訊息,如果當前沒有要處理的訊息,則block,之後我們會看到這個API的實現   
  28.             if (msg == null) {//呼叫了MessgeQueu的quit函式後,MessageQueue.next會返回null   
  29.                 // No message indicates that the message queue is quitting.   
  30.                 return;  
  31.             }  
  32.   
  33.             // This must be in a local variable, in case a UI event sets the logger   
  34.             Printer logging = me.mLogging;  
  35.             if (logging != null) {//藉助logging我們可以列印Looper中處理的訊息   
  36.                 logging.println(">>>>> Dispatching to " + msg.target + " " +  
  37.                         msg.callback + ": " + msg.what);  
  38.             }  
  39.   
  40.             msg.target.dispatchMessage(msg);//呼叫handler處理訊息   
  41.   
  42.             if (logging != null) {  
  43.                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
  44.             }  
  45.   
  46.             // Make sure that during the course of dispatching the   
  47.             // identity of the thread wasn't corrupted.   
  48.             final long newIdent = Binder.clearCallingIdentity();//選擇性無視   
  49.             if (ident != newIdent) {  
  50.                 Log.wtf(TAG, "Thread identity changed from 0x"  
  51.                         + Long.toHexString(ident) + " to 0x"  
  52.                         + Long.toHexString(newIdent) + " while dispatching to "  
  53.                         + msg.target.getClass().getName() + " "  
  54.                         + msg.callback + " what=" + msg.what);  
  55.             }  
  56.   
  57.             msg.recycle();//回收訊息到訊息池   
  58.         }  
  59.     }  
    /**
     * Quits the looper.
     *
     * Causes the {@link #loop} method to terminate as soon as possible.
     */
    public void quit() {
        mQueue.quit();
    }

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {//呼叫looper之前,需要先呼叫perpare,否則您懂的...
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();//不太明白這個函式,但不是重點可以無視
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block 獲取一個下一個訊息,如果當前沒有要處理的訊息,則block,之後我們會看到這個API的實現
            if (msg == null) {//呼叫了MessgeQueu的quit函式後,MessageQueue.next會返回null
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {//藉助logging我們可以列印Looper中處理的訊息
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);//呼叫handler處理訊息

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();//選擇性無視
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();//回收訊息到訊息池
        }
    }
    Looper.loop()函式是Looper類的核心函式,主要迴圈進行兩個操作:
  1. 從MessageQueue中獲取一個訊息,當前沒有訊息需要處理時,則block
  2. 呼叫message的Handler(target)處理訊息
    基本上,我們可以把Looper理解為一個死迴圈,Looper開始work以後,執行緒就進入了以訊息為驅動的工作模型。

    小結:
  1. 每個執行緒最多可以有一個Looper。
  2. 每個Looper有且僅有一個MessageQueue
  3. 每個Handler關聯一個MessageQueue,由該MessageQueue關聯的Looper執行(呼叫Hanlder.dispatchMessage)
  4. 每個MessageQueue可以關聯任意多個Handler
  5. Looper API的呼叫順序:Looper.prepare >> Looper.loop >> Looper.quit
  6. Looper的核心函式是Looper.loop,一般loop不會返回,直到執行緒退出,所以需要執行緒完成某個work時,請傳送訊息給Message(或者說Handler)

MessageQueue

    
    MessageQueue類是唯一包含native函式的類,我們先大致看一下,稍後C++的部分在詳細解釋:
  1. private native void nativeInit();    //初始化   
  2. private native void nativeDestroy(); //銷燬   
  3. private native void nativePollOnce(int ptr, int timeoutMillis); //等待<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">timeoutMillis指定的時間</SPAN>   
  4. private native void nativeWake(int ptr);//喚醒<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">nativePollOnce的等待</SPAN>  
    private native void nativeInit();    //初始化
    private native void nativeDestroy(); //銷燬
    private native void nativePollOnce(int ptr, int timeoutMillis); //等待<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">timeoutMillis指定的時間</span>
    private native void nativeWake(int ptr);//喚醒<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">nativePollOnce的等待</span>

    然後,我們再從建構函式看起:
  1.   
  2. Message mMessages;//資料域mMessages的型別雖然是Message,但是因為Message.next資料域的原因,其實mMessage是連結串列的第一個元素   
  3.   
  4. MessageQueue(boolean quitAllowed) {  
  5.     mQuitAllowed = quitAllowed;  
  6.     nativeInit();//初始化nativeMessageQueue   
  7. }  
    
    Message mMessages;//資料域mMessages的型別雖然是Message,但是因為Message.next資料域的原因,其實mMessage是連結串列的第一個元素

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        nativeInit();//初始化nativeMessageQueue
    }
    對應的,在銷燬的時候:
  1. @Override  
  2. protected void finalize() throws Throwable {  
  3.     try {  
  4.         nativeDestroy();//銷燬nativeMessageQueue   
  5.     } finally {  
  6.         super.finalize();  
  7.     }  
  8. }  
    @Override
    protected void finalize() throws Throwable {
        try {
            nativeDestroy();//銷燬nativeMessageQueue
        } finally {
            super.finalize();
        }
    }
    
    此外,MessageQueue提供了一組函式(e.g. hasMessage, removeMessage)來查詢和移除待處理的訊息,我們在前面的Handler類上看到的對應函式的實現就是呼叫這組函式。

    接下來,看看enqueueMessage函式,Handler函式就是呼叫這個函式把message放到MessageQueue中:
  1.     final boolean enqueueMessage(Message msg, long when) {  
  2.         if (msg.isInUse()) {//檢查msg是否在使用中,一會我們可以看到MessageQueue.next()在返回前通過Message.makeInUse函式設定msg為使用狀態,而我們之前看到過Looper.loop中通過呼叫呼叫Message.recycle(),把Message重置為未使用的狀態。   
  3.             throw new AndroidRuntimeException(msg + " This message is already in use.");  
  4.         }  
  5.         if (msg.target == null) {//msg必須知道由那個Handler負責處理它   
  6.             throw new AndroidRuntimeException("Message must have a target.");  
  7.         }  
  8.   
  9.         boolean needWake;  
  10.         synchronized (this) {  
  11.             if (mQuiting) {//如果已經呼叫MessageQueue.quit,那麼不再接收新的Message   
  12.                 RuntimeException e = new RuntimeException(  
  13.                         msg.target + " sending message to a Handler on a dead thread");  
  14.                 Log.w("MessageQueue", e.getMessage(), e);  
  15.                 return false;  
  16.             }  
  17.   
  18.             msg.when = when;  
  19.             Message p = mMessages;  
  20.             if (p == null || when == 0 || when < p.when) {//插到列表頭   
  21.                 // New head, wake up the event queue if blocked.   
  22.                 msg.next = p;  
  23.                 mMessages = msg;  
  24.                 needWake = mBlocked;//當前MessageQueue處於block狀態,所以需要喚醒   
  25.             } else {  
  26.                 // Inserted within the middle of the queue.  Usually we don't have to wake   
  27.                 // up the event queue unless there is a barrier at the head of the queue   
  28.                 // and the message is the earliest asynchronous message in the queue.   
  29.                 needWake = mBlocked && p.target == null && msg.isAsynchronous();//當且僅當MessageQueue因為Sync Barrier而block,並且msg為非同步訊息時,喚醒。 關於msg.isAsyncChronous(),請回去看看Handler.enqueueMessage函式和建構函式   
  30.                 Message prev;  
  31.                 for (;;) {<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 根據when的大小順序,插入到合適的位置</SPAN>   
  32.                     prev = p;  
  33.                     p = p.next;  
  34.                     if (p == null || when < p.when) {  
  35.                         break;  
  36.                     }  
  37.                     if (needWake && p.isAsynchronous()) {//如果在插入位置以前,發現非同步訊息,則不需要喚醒   
  38.                         needWake = false;  
  39.                     }  
  40.                 }  
  41.                 msg.next = p; // invariant: p == prev.next   
  42.                 prev.next = msg;  
  43.             }  
  44.         }  
  45.         if (needWake) {  
  46.             nativeWake(mPtr);//喚醒nativeMessageQueue   
  47.         }  
  48.         return true;  
  49.     }  
  50.    
  51.     final void quit() {  
  52.         if (!mQuitAllowed) {//UI執行緒的Looper訊息佇列不可退出   
  53.             throw new RuntimeException("Main thread not allowed to quit.");  
  54.         }  
  55.   
  56.   
  57.         synchronized (this) {  
  58.             if (mQuiting) {  
  59.                 return;  
  60.             }  
  61.             mQuiting = true;  
  62.         }  
  63.         nativeWake(mPtr);//喚醒nativeMessageQueue   
  64.     }  
    final boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {//檢查msg是否在使用中,一會我們可以看到MessageQueue.next()在返回前通過Message.makeInUse函式設定msg為使用狀態,而我們之前看到過Looper.loop中通過呼叫呼叫Message.recycle(),把Message重置為未使用的狀態。
            throw new AndroidRuntimeException(msg + " This message is already in use.");
        }
        if (msg.target == null) {//msg必須知道由那個Handler負責處理它
            throw new AndroidRuntimeException("Message must have a target.");
        }

        boolean needWake;
        synchronized (this) {
            if (mQuiting) {//如果已經呼叫MessageQueue.quit,那麼不再接收新的Message
                RuntimeException e = new RuntimeException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            }

            msg.when = when;
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {//插到列表頭
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;//當前MessageQueue處於block狀態,所以需要喚醒
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();//當且僅當MessageQueue因為Sync Barrier而block,並且msg為非同步訊息時,喚醒。 關於msg.isAsyncChronous(),請回去看看Handler.enqueueMessage函式和建構函式
                Message prev;
                for (;;) {<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 根據when的大小順序,插入到合適的位置</span>
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {//如果在插入位置以前,發現非同步訊息,則不需要喚醒
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
        }
        if (needWake) {
            nativeWake(mPtr);//喚醒nativeMessageQueue
        }
        return true;
    }
 
    final void quit() {
        if (!mQuitAllowed) {//UI執行緒的Looper訊息佇列不可退出
            throw new RuntimeException("Main thread not allowed to quit.");
        }


        synchronized (this) {
            if (mQuiting) {
                return;
            }
            mQuiting = true;
        }
        nativeWake(mPtr);//喚醒nativeMessageQueue
    }
    關於sync barrier,再補充點解釋: sync barrier是起到了一個阻塞器的作用,它可以阻塞when>它(即執行時間比它晚)的同步訊息的執行,但不影響非同步訊息。sync barrier的特徵是targe為null,所以它只能被remove,無法被執行。MessageQueue提供了下面兩個函式來控制MessageQueue中的sync barrier(如何覺得sync barrier和非同步訊息難以理解的話,選擇性無視就好,因為它們不妨礙我們理解Android訊息機制的原理):
  1. final int enqueueSyncBarrier(long when) {  
  2.     // Enqueue a new sync barrier token.   
  3.     // We don't need to wake the queue because the purpose of a barrier is to stall it.   
  4.     synchronized (this) {  
  5.         final int token = mNextBarrierToken++;  
  6.         final Message msg = Message.obtain();  
  7.         msg.arg1 = token;  
  8.   
  9.         Message prev = null;  
  10.         Message p = mMessages;  
  11.         if (when != 0) {  
  12.             while (p != null && p.when <= when) {  
  13.                 prev = p;  
  14.                 p = p.next;  
  15.             }  
  16.         }  
  17.         if (prev != null) { // invariant: p == prev.next   
  18.             msg.next = p;  
  19.             prev.next = msg;  
  20.         } else {  
  21.             msg.next = p;  
  22.             mMessages = msg;  
  23.         }  
  24.         return token;  
  25.     }  
  26. }  
  27.   
  28. final void removeSyncBarrier(int token) {  
  29.     // Remove a sync barrier token from the queue.   
  30.     // If the queue is no longer stalled by a barrier then wake it.   
  31.     final boolean needWake;  
  32.     synchronized (this) {  
  33.         Message prev = null;  
  34.         Message p = mMessages;  
  35.         while (p != null && (p.target != null || p.arg1 != token)) {  
  36.             prev = p;  
  37.             p = p.next;  
  38.         }  
  39.         if (p == null) {  
  40.             throw new IllegalStateException("The specified message queue synchronization "  
  41.                     + " barrier token has not been posted or has already been removed.");  
  42.         }  
  43.         if (prev != null) {  
  44.             prev.next = p.next;  
  45.             needWake = false;  
  46.         } else {  
  47.             mMessages = p.next;  
  48.             needWake = mMessages == null || mMessages.target != null;//其實我覺得這邊應該是needWake = mMessages != null && mMessages.target != null   
  49.         }  
  50.         p.recycle();  
  51.     }  
  52.     if (needWake) {  
  53.         nativeWake(mPtr);//有需要的話,喚醒nativeMessageQueue   
  54.     }  
  55. }  
    final int enqueueSyncBarrier(long when) {
        // Enqueue a new sync barrier token.
        // We don't need to wake the queue because the purpose of a barrier is to stall it.
        synchronized (this) {
            final int token = mNextBarrierToken++;
            final Message msg = Message.obtain();
            msg.arg1 = token;

            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }

    final void removeSyncBarrier(int token) {
        // Remove a sync barrier token from the queue.
        // If the queue is no longer stalled by a barrier then wake it.
        final boolean needWake;
        synchronized (this) {
            Message prev = null;
            Message p = mMessages;
            while (p != null && (p.target != null || p.arg1 != token)) {
                prev = p;
                p = p.next;
            }
            if (p == null) {
                throw new IllegalStateException("The specified message queue synchronization "
                        + " barrier token has not been posted or has already been removed.");
            }
            if (prev != null) {
                prev.next = p.next;
                needWake = false;
            } else {
                mMessages = p.next;
                needWake = mMessages == null || mMessages.target != null;//其實我覺得這邊應該是needWake = mMessages != null && mMessages.target != null
            }
            p.recycle();
        }
        if (needWake) {
            nativeWake(mPtr);//有需要的話,喚醒nativeMessageQueue
        }
    }

    重頭戲又來了:
  1. final Message next() {  
  2.       int pendingIdleHandlerCount = -1// -1 only during first iteration   
  3.       int nextPollTimeoutMillis = 0;  
  4.   
  5.       for (;;) {  
  6.           if (nextPollTimeoutMillis != 0) {  
  7.               Binder.flushPendingCommands();//不太理解,選擇性無視   
  8.           }  
  9.           nativePollOnce(mPtr, nextPollTimeoutMillis);//等待nativeMessageQueue返回,最多等待nextPollTimeoutMillis毫秒   
  10.   
  11.           synchronized (this) {  
  12.               if (mQuiting) {//如果要退出,則返回null   
  13.                   return null;  
  14.               }  
  15.   
  16.               // Try to retrieve the next message.  Return if found.   
  17.               final long now = SystemClock.uptimeMillis();  
  18.               Message prevMsg = null;  
  19.               Message msg = mMessages;  
  20.               if (msg != null && msg.target == null) {//下一個訊息為sync barrier   
  21.                   // Stalled by a barrier.  Find the next asynchronous message in the queue.   
  22.                   do {  
  23.                       prevMsg = msg;  
  24.                       msg = msg.next;  
  25.                   } while (msg != null && !msg.isAsynchronous());//因為存在sync barrier,僅有非同步訊息可以執行,所以尋在最近的非同步訊息   
  26.               }  
  27.               if (msg != null) {  
  28.                   if (now < msg.when) {  
  29.                       // Next message is not ready.  Set a timeout to wake up when it is ready.   
  30.                       nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);//訊息還沒到執行的時間,所以我們繼續等待msg.when - now毫秒   
  31.                   } else {  
  32.                       // Got a message.   
  33.                       mBlocked = false;//開始處理訊息了,所以不再是blocked狀態   
  34.                       if (prevMsg != null) {  
  35.                           prevMsg.next = msg.next;//從連結串列中間移除message   
  36.                       } else {  
  37.                           mMessages = msg.next;//從連結串列頭移除message   
  38.                       }  
  39.                       msg.next = null;  
  40.                       if (false) Log.v("MessageQueue""Returning message: " + msg);  
  41.                       msg.markInUse();//標記msg正在使用   
  42.                       return msg;//返回到Looper.loop函式   
  43.                   }  
  44.               } else {  
  45.                   // No more messages.   
  46.                   nextPollTimeoutMillis = -1;//沒有訊息可以處理,所以無限制的等待   
  47.               }  
  48.   
  49.               // If first time idle, then get the number of idlers to run.   
  50.               // Idle handles only run if the queue is empty or if the first message   
  51.               // in the queue (possibly a barrier) is due to be handled in the future.   
  52.               if (pendingIdleHandlerCount < 0  
  53.                       && (mMessages == null || now < mMessages.when)) {<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 目前無訊息可以處理,可以執行IdleHandler</SPAN>   
  54.                   pendingIdleHandlerCount = mIdleHandlers.size();  
  55.               }  
  56.               if (pendingIdleHandlerCount <= 0) {  
  57.                   // No idle handlers to run.  Loop and wait some more.   
  58.                   mBlocked = true;  
  59.                   continue;  
  60.               }  
  61.   
  62.               if (mPendingIdleHandlers == null) {  
  63.                   mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];  
  64.               }  
  65.               mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);  
  66.           }  
  67.   
  68.           // Run the idle handlers.   
  69.           // We only ever reach this code block during the first iteration.   
  70.           for (int i = 0; i < pendingIdleHandlerCount; i++) {  
  71.               final IdleHandler idler = mPendingIdleHandlers[i];  
  72.               mPendingIdleHandlers[i] = null// release the reference to the handler   
  73.   
  74.               boolean keep = false;  
  75.               try {  
  76.                   keep = idler.queueIdle();  
  77.               } catch (Throwable t) {  
  78.                   Log.wtf("MessageQueue""IdleHandler threw exception", t);  
  79.               }  
  80.   
  81.               if (!keep) {  
  82.                   synchronized (this) {  
  83.                       mIdleHandlers.remove(idler);  
  84.                   }  
  85.               }  
  86.           }  
  87.   
  88.           // Reset the idle handler count to 0 so we do not run them again.   
  89.           pendingIdleHandlerCount = 0;//Looper.looper呼叫一次MessageQueue.next(),只允許呼叫一輪IdleHandler   
  90.   
  91.           // While calling an idle handler, a new message could have been delivered   
  92.           // so go back and look again for a pending message without waiting.   
  93.           nextPollTimeoutMillis = 0;//因為執行IdleHandler的過程中,可能有新的訊息到來,所以把等待時間設定為0   
  94.       }  
  95.   }  
  final Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();//不太理解,選擇性無視
            }
            nativePollOnce(mPtr, nextPollTimeoutMillis);//等待nativeMessageQueue返回,最多等待nextPollTimeoutMillis毫秒

            synchronized (this) {
                if (mQuiting) {//如果要退出,則返回null
                    return null;
                }

                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {//下一個訊息為sync barrier
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());//因為存在sync barrier,僅有非同步訊息可以執行,所以尋在最近的非同步訊息
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);//訊息還沒到執行的時間,所以我們繼續等待msg.when - now毫秒
                    } else {
                        // Got a message.
                        mBlocked = false;//開始處理訊息了,所以不再是blocked狀態
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;//從連結串列中間移除message
                        } else {
                            mMessages = msg.next;//從連結串列頭移除message
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();//標記msg正在使用
                        return msg;//返回到Looper.loop函式
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;//沒有訊息可以處理,所以無限制的等待
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 目前無訊息可以處理,可以執行IdleHandler</span>
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;//Looper.looper呼叫一次MessageQueue.next(),只允許呼叫一輪IdleHandler

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;//因為執行IdleHandler的過程中,可能有新的訊息到來,所以把等待時間設定為0
        }
    }
              為了方便大家理解Message的工作原理,先簡單描述nativeWake,和natePollonce的作用:
  1. nativePollOnce(mPtr, nextPollTimeoutMillis);暫時無視mPtr引數,阻塞等待nextPollTimeoutMillis毫秒的時間返回,與Object.wait(long timeout)相似
  2. nativeWake(mPtr);暫時無視mPtr引數,喚醒等待的nativePollOnce函式返回的執行緒,從這個角度解釋nativePollOnce函式應該是最多等待nextPollTimeoutMillis毫秒

    小結:
  1. MessageQueue作為一個容器,儲存了所有待執行的訊息。
  2. MessageQueue中的Message包含三種型別:普通的同步訊息,Sync barrier(target = null),非同步訊息(isAsynchronous() = true)。
  3. MessageQueue的核心函式為enqueueMessage和next,前者用於向容器內新增Message,而Looper通過後者從MessageQueue中獲取訊息,並實現無訊息情況下的等待。
  4. MessageQueue把Android訊息機制的Java實現和C++實現聯絡起來。
    本來我是想一口氣把java實現和C++實現都寫完的,但是,無奈最近工作和個人事務都比較多,稍後為大家奉上C++實現的解析。
    

相關文章