Handler的前世今生4 —— Handler

Handler文檔

我們使用Handler其實就是就是2個功能:

  1. 發送消息
  2. 處理消息

但是在這之前 ,我們要做好準備工作,那就是必須得有LooperMessageQueue才行。

Handler就類似一個快遞站,如果你沒有對應的 運輸設備(Looper)存儲倉庫(MessageQueue),就沒辦法運行啊。

1. 使用Handler的前提條件

通過源碼,我們發現Handler其實有很多構造函數,但是最終都指向一個:

 public Handler(@Nullable Callback callback, boolean async) {
      // 此處省略監聽 內存泄漏 的代碼...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

我們可以創建Handler都是要先獲取到LooperMessageQueue 的.


2. Handler發送消息

消息的發送主要分爲三種發送:

  1. 普通發送;
  2. 定時發送;
  3. 延時發送;

2.1 send方式

這些是Handler類關於sendMessage的方法。
sengMessage的重載

不得不感慨一下,如果使用Kotlin重寫Handler,就不會存在這麼多的重載方法啦。

那麼Handler是如何處理三者(普通,定時,延時)的關係呢?這裏不妨可以思考一下…

具體看一下源碼的設計,驗證一下我們的猜想:

2.1.1. 普通發送:sendMessage()

通過延時發送(sendMessageDelayed),設置延時爲0來實現即時發送的。

  public final boolean sendMessage(@NonNull Message msg) {
  		// 注意這裏,通過調用延時0發送,即:立刻發送
        return sendMessageDelayed(msg, 0);
    }

2.1.2. 延時發送:sendMessageDelayed()

具體的通過定時發送(sendMessageAtTime) 來實現的延時功能

 public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        // 這裏:調用的定時發送—— 當前時間 + 延時時間
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
2.1.3. 定時發送:sendMessageAtTime()

消息在這裏進行入隊列操作,強調一點,真正的入隊是由MessageQueue操作的

  public boolean sendMessageAtTime(@NonNull 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);
    }

2.2 post方式

我相信大家在開發過程中,使用post() 的情況可能會更多一些吧。post 方式我們在使用過程上基本上都是與Runnable打交道,並未見到Message的身影。

難道Handler的消息機制不適用於post方式?今天我們去一探究竟。
post方式

先看一下使用最多的post()方法吧。

2.2.1. post()方法
  public final boolean post(@NonNull Runnable r) {
  		// 這裏有個getPostMessage()方法
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
2.2.2. getPostMessage()

該方法給我們返回Message,將我們的Runnable賦值給Messagecallback屬性。關於Message的更多內容,可以查看 Handler的前世今生3——Message

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

通過getPostMessage() 返回對應的Message對象,無縫對接 send方式。本質最後都是通過**sendMessageAtTime()**將消息入隊。

2.3 消息的入隊操作

強調一下:入隊操作的主角是MessageQueue

  private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        // 標示一下,這是我的消息
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 這裏纔是真正的入隊噢...
        return queue.enqueueMessage(msg, uptimeMillis);
    }

2.4 消息的複用obtain()

可以看到,消息的複用本質上還是Message來做的,這裏僅僅是做了一層封裝,畢竟Handler纔是Message的使用者。

 public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

3. Handler 處理消息

我們都知道Handler是自產自銷,接下來我們就來討論一下Handler 是如何處理消息的。

我們知道在Looper的loop()方法中,handler調用了其dispatchMessage()

/**
 * 最常用的方式
 */
 public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        boolean handleMessage(@NonNull Message msg);
    }
    
    /**
     * 繼承Handler時重寫該方法 
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(@NonNull Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
    	// post方式,則最終還是在post的runnable中執行
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        // send方式,創建Handler中是否傳入Callback,對應進行處理
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            
            handleMessage(msg);
        }
    }
  private static void handleCallback(Message message) {
  		// 妙啊...
        message.callback.run();
    }

可以看到消息處理操作是在Handler中進行的。消息出隊列是在Looper中的loop()中進行的。

完美演繹啊,不得不感慨一下,這個設計真是太棒啦…


4. Handler的清理操作

在實際開發中,我們一般都會在Activity要銷燬時,調用removeCallbacksAndMessages() 方法。

Remove any pending posts of callbacks and sent messages
其實就是MessageQueue清除post的回調和send的消息。

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

5. 總結

  1. Handler的發送消息(post,send)最終都是sendMessageAtTime() 實現。
  2. post()是根據getPostMessage(),將RunnableMessage 進行綁定的。
  3. 消息的入隊操作都是靠enqueueMessage()
  4. dispatchMessage() 分情況處理消息。

到這裏,其實我們會發現,關於Message的重要屬性 taget , callbackmAsynchronous 都已經在Handler中完成賦值,唯有 when屬性 沒有在Handler進行處理,奇哉怪哉…


希望大家能繼續查看:Handler的前世今生5 —— MessageQueue

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章