天天看點

Handler Looper源碼解析(Android消息傳遞機制)

Android的Handler類應該是常用到的,多用于線程間的通信,以及子線程發送消息通知UI線程重新整理View等等。這裡我主要總結下我對整個消息傳遞機制,包括Handler,Looper,Message,MessageQueue類的了解。

Looper類:每一個線程都隻能擁有一個Looper對象,這裡Android是通過将Looper對象設定為目前線程的線程局部變量(這裡涉及到ThreadLocal類),可以通過調用Looper.prepare()方法來使目前線程擁有一個Looper對象(主線程不用調用,因為主線程本身已經是擁有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對象,就會報錯。*/
        }
        sThreadLocal.set(new Looper(quitAllowed));/*建立Looper對象并設定為目前線程的線程局部變量。*/
    }
           

 而Looper類的主要作用是進行消息循環,Looper類維護了一個MesageQueue,通過不停調用loop()方法來取出MeesageQueue中的Message并進行相應的處理。

public static void loop() {
        final Looper me = myLooper();  /*得到目前線程的Looper對象*/
        if (me == null) {
            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
            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.recycle();/* 回收msg(重複利用Message對象) */
        }
    }
           

這個留意到loop()方法裡對Message的處理方式是調用msg.target.dispatchMessage(msg);,關于這個方法,我們了解完Handler後再看。

MeesageQueue:Message隊列,隊列就不詳解了,先進先出。

Handler:Handler的作用主要是分發資訊 相關方法有:

        post(Runnable)

        postAtTime(Runnable,long)

        postDelayed(Runnable long)

        sendEmptyMessage(int)

        sendMessage(Message)

        sendMessageAtTime(Message,long)

        sendMessageDelayed(Message,long)

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


  public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }


 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

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);
    }
           

 發現這些方法最後都是調用enqueueMessage(),看看這個方法的源碼

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
           

 調用了MessageQueue的enqueueMessage方法,将Message對象加入了隊列中去

再看看這幾個方法

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

 public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }

public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
           

 發現post()系列的方法最後都是調用sendMessage系列的方法隻是傳入的Message對象有所不同,我們再看看getPostMessage()

private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }
           

 發現其實就是把Runnable對象賦給Message的callback。通過以上代碼的分析,基本上對整個消息機制有個概念了,當我們調用Handler的sendMessage()或post()等一系列方法時,Handler會将消息加入到MessageQueue中,這個MessageQueue為Handler對應的Looper對象所維護的queue(建立Handler時可以傳入Looper對象,無參情況下為目前線程的Looper,想具體了解可以看下Handler的構造函數,這裡不再贅述)然後由Looper類的loop()方法将消息取出。并做處理。至于怎麼處理,我們就要看下msg.target.dispatchMessage(msg)這個方法了。我們知道msg的target是一個Handler對象,看下這個方法的源碼

public void dispatchMessage(Message msg) {
/* 如果callback不為空,即發送消息的時候傳入了Runnable對象,也就是調用的是post()系列的方法。那麼就會執行handleCallback()這個方法,否則執行handleMessage() */
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
           

 handleMessge()方法想必大家都很熟悉,這個方法是我們new一個Handler對象時常常會去重寫的,然後處理消息時會回調這個方法。再看看handleCallback()

private static void handleCallback(Message message) {
        message.callback.run();
    }
           

 代碼很簡單,就是調用了callback的run()方法。這裡要特别注意的是調用的是run()而不是start(),這意味着将不會另起一個線程。而是在Looper對象所在的線程執行。至于為什麼這麼做筆者認為由于這樣做即使是多次post也不需要開啟多個線程,大大提高了程式的性能,同時,在某些情況下,我們希望能夠順序執行callback,那麼使用這個方法無疑是非常棒的。當然,如果是要并發執行作那麼就得使用其他法子了。總的來說post()方法相當于sendMessage()+handleMessage()使用方式的一種變體。