1. 程式人生 > >Android訊息機制剖析—Looper篇

Android訊息機制剖析—Looper篇

本篇文章在android6.0基礎上分析。

Looper在訊息機制中扮演的角色是創造無限迴圈從Messagequeue中取得訊息然後分發。

一、Looper的建立

只要呼叫Looper.prepare()方法之後,然後再Looper.loop()即可,這裡兩個方法都是static方法,表面沒有任何Looper物件的參與,具體如何

先來看下prepare()這個方法:

   public static void prepare() {
        prepare(true);//呼叫私有方法
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");//限制Looper.prepare()只能呼叫一次
        }
        sThreadLocal.set(new Looper(quitAllowed));//這裡才是Looper物件的建立,放入sThreadLocal中
    }
<pre name="code" class="java">   private Looper(boolean quitAllowed) {
      mQueue = new MessageQueue(quitAllowed);//創造了Messagequeue
      mThread = Thread.currentThread();
  }


程式碼中提到了sThreadLocal變數,型別為ThreadLocal,ThreadLocal的特殊作用在:可以多個執行緒共享,但set和get的作用域都是執行緒內的。例如thread-1和thread-2兩個執行緒都呼叫了Loop.prepare(),使用的ThreadLocal是同一個物件,但set()放入的Looper是分別屬於各自的。

二、Looper的loop()

先看原始碼,核心的地方被我加了註釋。
 public static void loop() {
        final Looper me = myLooper();//從ThreadLocal中獲取本執行緒的Looper物件,這個物件是用Looper.prepare建立的
        if (me == null) {//如果沒有Looper.prepare,就呼叫了loop就會丟擲下面的異常
            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 (;;) {//最重要的就是這個死迴圈,4.0之前是while(true)
            Message msg = queue.next(); // might block,MessageQueue沒有訊息,執行next()就會執行緒阻塞,直到有訊息為止。
            if (msg == 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.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            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.recycleUnchecked();
        }
    }
這個Loop是訊息機制的核心所在,尤其是for(;;)這個死迴圈;上面程式碼關注四個點: (1)呼叫myLooper來判斷是否已經用Looper.prepare()建立了Looper物件(ThreadLocal儲存) (2)Loop迴圈每次都會從MessageQueue中獲取一個Message(next()方法),如果沒有則執行緒阻塞。 (3)如果獲取了一個Message,則呼叫target(Hanlder)的dispatchMessage方法來分派處理這個Message。 (4)最後呼叫msg.recycleUnchecked(),來格式化這個Message,重新進入訊息池;
  public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//如果是執行緒thread-1呼叫,則獲得的thread-1的Looper,如果是thread-2調動,獲得的是thread-2的looper。
    }