Android消息機制

Android消息機制主要指的是Handler的運行機制。
(註意,消息機制中的Handler是android.os包下的Handler,不是java.util.logging包中的Handler,開發中註意不要到錯包。)
Handler是消息機制的上層接口。Handler將任務切換到handler所在的線程執行。
與handler相關的有MessageQueue、Looper。其中,
MessageQueue中文名稱是消息隊列,內部存儲瞭一組消息,並以隊列的形式向外提供插入刪除操作。MessageQueue以隊列的形式命名,而內部實現是單鏈表。內部提供瞭next方法讀取一條消息,並從消息隊列中刪除。
Looper是個無限循環,當調用Looper.prepare和Looper.loop方法後Looer就開始工作瞭。Looper以無限循環方式檢查是否有消息,有就處理,無就等待。Looer中有個ThreadLocal對象,用來存儲每個線程的數據,通過ThreadLocal可以獲取每個線程的Looper,ThreadLocal保證每個線程的數據互不幹擾。
流程
Handler創建時,會使用當前線程的Looper來構造內部的消息循環系統。每個Handler對應一個Looper。如果Handler所在的線程沒有對應的Looer,則會拋出一個這樣的異常信息:

Can't create handler inside thread that has not called Looper.prepare()。 

解決辦法就是,在Handler創建之前,調用Looper.Prepare初始化looper,並在handler創建後調用Looper.loop開啟循環,若不調用Looper.loop則Looper是無法工作的。
這樣的情況一般出現在子線程創建handler對象的時候。為什麼主線程我們沒有創建Looper對象,卻沒有拋出這樣的異常呢?
原因就是在MainThread中,系統給我們初始化瞭Looper對象。查看源碼可發現這句:

Looper.prepareMainLooper();//創建主線程Looper和MessageQueue
Looper.Loop();//開啟主線程Looper

當調用handler.post(Runnable runnable)方法後,會將Runnable對象投遞到handler內部的Looer中處理。也可以通過Handler.sendMessage(Message msg)方法來發送一個消息,也是會在Looer中處理。查看源碼得知,handler.post方法最終調用的也是handler.send方法來實現的。

當handler.send方法被調用時,它會調用MessageQueue的enqueueMessage將消息存放到MessageQueue中。當Looper檢測到時,會調用next方法讀取此消息,並從MessageQueue中刪除。

相關代碼如下:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

看一下DispatchMessage方法執行流程:
在dispatchMessage方法中有以下幾個分支:
先檢查Message的callback(是一個Runnable類型的對象)是否為null,如果不為null就執行HandlerCallBack來處理消息;
檢查mCallback(是一個CallBack接口類型對象)是否為null,如果不為null,就執行mCallback接口對象的handlerMessage方法來處理消息;
最後則是調用handler的handlerMessage方法來處理消息。

題外話,子線程為什麼不能直接訪問UI?
android的控件不是線程安全的。在線程中訪問ui,可能導致ui不可控。考慮到ui訪問效率又不能是主線程阻塞,故不能采用加鎖機制。所以在
Android 4.0以後做出瞭這樣的規定,要求子線程不能訪問ui,否則會直接拋出異常。異常信息是這樣的:

Only the original thread that created a view hierarchy can touch its views.

Handler的應用場景
通常在子線程中將結果發送給主線程,通知主線程更新ui。
也可以在主線程中將任務加入到消息隊列順序執行。

源碼分析

//可以直接實現此接口來初始化handler,而不必去實現創建Handler的子類
public interface Callback {
        public boolean handleMessage(Message msg);
    }
//handlerMessage是一個空方法,子類若要通過這種方式處理消息,子類必須自己實現
    public void handleMessage(Message msg) {
    }
//消息處理,分析見上述
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

下面是handler的幾個構造方法:

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }
//使用指定的Looper對象構造handler
    public Handler(Looper looper) {
        this(looper, null, false);
    }
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
    public Handler(boolean async) {
        this(null, async);
    }

 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class 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;
        mAsynchronous = async;
    }

 public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

handler的幾個構造,由於代碼不復雜,這裡不再說明。
接下來看一系列的obtainMessage方法,及它們的重載:

//Message.obtainMessage獲取的結果是通過Message.Target設置的值
   public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
     public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }
    public final Message obtainMessage(int what, Object obj)
    {
        return Message.obtain(this, what, obj);
    }
     public final Message obtainMessage(int what, int arg1, int arg2)
    {
        return Message.obtain(this, what, arg1, arg2);
    }
     public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
    {
        return Message.obtain(this, what, arg1, arg2, obj);
    }

接著看幾個比較重要的方法:

//post方法與postDelayed方法一樣,最終調用的是sendMessageDelayed方法
  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);
    }
    //從消息隊列中移除指定的Runnable對象

     public final void removeCallbacks(Runnable r)
    {
        mQueue.removeMessages(this, r, null);
    }
//移除消息隊列中的Runnable對象,如果object參數不為null 則會移除所有的
     public final void removeCallbacks(Runnable r, Object token)
    {
        mQueue.removeMessages(this, r, token);
    }

下面是sendmessage的一系列方法,

//將消息添加到消息隊列,如果添加成功會返回true,否則返回false
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
//將一個僅有what值的message添加到消息隊列,添加成功返回true,否則返回false
    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

    //在指定的時間後發送一個僅有what值的message,添加到消息隊列
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

    //在指定的時間將僅有what值的message添加到消息隊列

    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);
    }
//將消息加入消息隊列
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    //從消息隊列中移除指定what值的message
    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }


    public final void removeMessages(int what, Object object) {
        mQueue.removeMessages(this, what, object);
    }

    public final void removeCallbacksAndMessages(Object token) {
        mQueue.removeCallbacksAndMessages(this, token);
    }

接下來的代碼,是創建瞭一個IMessager的實現類。可以看出使用瞭Binder機制。為瞭實現對使用Messenger跨進程發送消息的處理。涉及到進程通信,這裡先不多講。

final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

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

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

    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *