Android Handler之Handler消息取出和處理 Handler消息取出和處理

Handler消息取出和處理

消息的取出

消息的取出主要是通過Looper的loop方法。
Looper.loop()主要是消息循環,從消息隊列中獲取消息,分發消息到Handler中。
查看一下loop的源碼。

public static void loop() {

        // ---  1.獲取當前Looper的消息隊列MessageQueue -----
        
        // 第一步
        // 獲取當前Looper對象
    final Looper me = myLooper();
    // myLooper()的作用是返回sThreadLocal存儲的Looper實例
    // 若me爲null,則拋出異常
    // 所以在執行loop()方法之前,必須執行prepare()方法,prepare()            //的作用是創建Looper實例
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    
    // 第二步
    // 獲取Looper實例中的消息隊列對象MessageQueue
    final MessageQueue queue = me.mQueue;

   // ......代碼省略

        //------ 2. 消息循環,無限循環 --------------
        
        // 第三步
    for (;;) {
            // 從MessageQueue中取出消息
            // 第四步
        Message msg = queue.next(); // might block
        // 如果消息爲空,則退出循環
        if (msg == null) {
        // No message indicates that the message queue is quitting.
            return;
        }

  // ......代碼省略
        final long dispatchEnd;
        try {
        

                // 第五步
                // 分發消息到對應的Handler
                // 把消息派發到msg的target屬性
                //target屬性實際上是一個handler對象
            msg.target.dispatchMessage(msg);
            
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        // ......代碼省略
    
      // 第六步
            // 回收消息
        msg.recycleUnchecked();
    }

}

消息循環Looper.loop(),主要作用的取出消息,通過以上代碼分析,大致分爲六步:

  • 第一步,獲取Looper對象
  • 第二步,獲取Looper實例中的消息隊列對象MessageQueue
  • 第三步,while()無限循環遍歷
  • 第四步,通過queue.next()從MessageQueue中取出一個Message對象
  • 第五步,通過msg.target.dispatchMessage(msg)來處理消息
  • 第六步,通過 msg.recycleUnchecked()來回收消息

其中第一二三步就別少了,第六步在
Message源碼

下面介紹第四步和第五步。

MessageQueue.next()方法

MessageQueue.next()主要是從MessageQueue中取出一個Message對象,源碼如下:

Message next() {
    //mPtr是關聯到native層的一個long型變量,只有當MessageQueue被
    // 拋棄的時候(調用disposed()方法),mPtr才爲0,這時直接return
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
         // 記錄空閒時處理的IdlerHandler的數量
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    
    // native層用到的變量,在nativePollOnce(ptr,
    //nextPollTimeoutMillis)使用,
    //如果nextPollTimeoutMillis=-1,一直阻塞不會超時,
    //如果nextPollTimeoutMillis=0,不會阻塞,立即返回,
    //如果nextPollTimeoutMillis>0,最長阻塞nextPollTimeoutMillis
    //毫秒(超時),如果期間有程序喚醒會立即返回。
    int nextPollTimeoutMillis = 0;
  
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        
                // 阻塞方法
        nativePollOnce(ptr, nextPollTimeoutMillis);
                // 同步鎖
        synchronized (this) {
         // 獲取開機到現在的時間
         final long now = SystemClock.uptimeMillis();
         
         //標記前一個message
         Message prevMsg = null;
         //獲取消息隊列中鏈表表頭的第一個元素 
         Message msg = mMessages;
         //判斷Message是否是同步屏障,如果是則執行循環,攔截所有同步消                     //息,直到取到第一個異步消息爲止。
         if (msg != null && msg.target == null) {
         // 如果進入這個循環,則表示MessageQueue的第一個message就是 
         //同步屏障消息
          // 循環遍歷,攔截所有同步消息,直到取出第一個異步消息
             do {
                  prevMsg = msg;
                  msg = msg.next;
          //退出循環的條件,msg==null,表示循環結束,
          //msg.isAsynchronous()爲ture表示是異步消息,則退出循環
                } while (msg != null &&!msg.isAsynchronous());
            }
          
         if (msg != null) {
         //判斷msg是否達到了執行時間
            if (now < msg.when) {
            //msg沒有達到執行時間,設置一下阻塞時間
            //nextPollTimeoutMillis,進入下次循環的時候會調用
            //nativePollOnce(ptr,nextPollTimeoutMillis)進行阻塞
            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
              } else {
              //msg已到執行時間
              //此時有消息,不能阻塞
                 mBlocked = false;
               //如果還有上一個元素
                 if (prevMsg != null) {
                 //上一個元素的next越過自己指向下一個元素
                      prevMsg.next = msg.next;
                  } else {
                  //如果沒有上一個元素,說明是消息隊列的頭元素,直接
                  //讓第二個元素變成頭元素
                     mMessages = msg.next;
                  }
                  //msg要取出,msg的next指向null
                  msg.next = null;
                  if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                  //設置msg爲正在使用的狀態
                  msg.markInUse();
                  // 返回msg
                  return msg;
                }
            } else {
             //沒有消息,會一直阻塞,直到被喚醒
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            //如果是退出狀態,關閉消息隊列,返回null,拋棄MessageQueue
            if (mQuitting) {
                dispose();
                return null;
            }
            
// 下面的代碼是處理一些不緊急的任務
// 如果沒有符合條件的消息,會處理一些不緊急的任務
// 每次調用MessageQueue.next(),這些代碼只執行一次
            
            if (pendingIdleHandlerCount < 0
                  && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount =mIdleHandlers.size();
            }
            
            // 當執行過一次不緊急任務時,pendingIdleHandlerCount爲
            //0,此時不會執行下面的代碼,直接開始下一步循環
            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.
        //開始循環執行所有的IdleHandler,並且根據返回值判斷是否保留
        //IdleHandler
        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(TAG, "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.
        // IdleHandler只會在消息隊列阻塞之前執行一次,執行之後改標示設
        //置爲0,之後就不會再執行,一直到下一次調MessageQueue.next() 
        //方法。
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        //當執行了IdleHandler 的 處理之後,會消耗一段時間,這時候消息
        //隊列裏的可能有消息已經到達可執行時間,所以重置該變量回去重新檢
        //查消息隊列。
        nextPollTimeoutMillis = 0;
    }
}

總的來說,MessageQueue的next()方法獲取一個Message的時候,會執行下面的操作:

  • MessageQueue先判斷消息隊列中是否有同步屏障消息的存在,如果有的話,會循環取出第一個異步消息。

  • 當MessageQueue沒有可以處理的消息的時候,它會進入阻塞狀態,等待新消息的到來,在阻塞之前它會執行一次 IdleHandler處理不緊急的任務,所謂的阻塞其實就是不斷的循環查看是否有新的消息進入隊列中。

  • 當MessageQueue被關閉的時候,其成員變量mQuitting會被標記爲true,
    然後next()返回null,在Looper.loop()的源碼中可以看到,當獲取的message爲null時,會直接return。

msg.target.dispatchMessage(msg)

msg.target.dispatchMessage(msg)主要是進行消息的分發。

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
        // 1
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
            // 2
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
  • 1.如果msg.callback不爲空,則執行handleCallback(Message),然後最終調用message.callback.run()。
  • 2.如果msg.callback爲空,但mCallback不爲空,則執行mCallback.handleMessage(msg)。
  • 3.如果msg.callback 爲空,且mCallback也爲空,則執行handleMessage()方法。

在大多數情況下,消息分發後的處理是第三種情況,即handleMessage(msg),這一般是通過複寫該方法的方式實現消息處理的業務邏輯。

以上就是消息的取出和處理的全部內容。

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