Android Handler之Handler消息取出和處理

Handler消息取出和處理

消息的取出

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

public static void loop() {

        // ---  1.獲取當前Looper的消息隊列MessageQueue -----
        
        // 第一步
        // 獲取當前Looper對象
    final Looper me = myLooper();
    // myLooper()的作用是返回sThreadLocal存儲的Looper實例
    // 若me為null,則拋出異常
    // 所以在執(zhí)行l(wèi)oop()方法之前,必須執(zhí)行prepare()方法,prepare()            //的作用是創(chuàng)建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. 消息循環(huán),無限循環(huán) --------------
        
        // 第三步
    for (;;) {
            // 從MessageQueue中取出消息
            // 第四步
        Message msg = queue.next(); // might block
        // 如果消息為空,則退出循環(huán)
        if (msg == null) {
        // No message indicates that the message queue is quitting.
            return;
        }

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

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

}

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

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

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

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

MessageQueue.next()方法

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

Message next() {
    //mPtr是關聯(lián)到native層的一個long型變量,只有當MessageQueue被
    // 拋棄的時候(調用disposed()方法),mPtr才為0,這時直接return
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
         // 記錄空閑時處理的IdlerHandler的數(shù)量
    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) {
         // 獲取開機到現(xiàn)在的時間
         final long now = SystemClock.uptimeMillis();
         
         //標記前一個message
         Message prevMsg = null;
         //獲取消息隊列中鏈表表頭的第一個元素 
         Message msg = mMessages;
         //判斷Message是否是同步屏障,如果是則執(zhí)行循環(huán),攔截所有同步消                     //息,直到取到第一個異步消息為止。
         if (msg != null && msg.target == null) {
         // 如果進入這個循環(huán),則表示MessageQueue的第一個message就是 
         //同步屏障消息
          // 循環(huán)遍歷,攔截所有同步消息,直到取出第一個異步消息
             do {
                  prevMsg = msg;
                  msg = msg.next;
          //退出循環(huán)的條件,msg==null,表示循環(huán)結束,
          //msg.isAsynchronous()為ture表示是異步消息,則退出循環(huán)
                } while (msg != null &&!msg.isAsynchronous());
            }
          
         if (msg != null) {
         //判斷msg是否達到了執(zhí)行時間
            if (now < msg.when) {
            //msg沒有達到執(zhí)行時間,設置一下阻塞時間
            //nextPollTimeoutMillis,進入下次循環(huán)的時候會調用
            //nativePollOnce(ptr,nextPollTimeoutMillis)進行阻塞
            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
              } else {
              //msg已到執(zhí)行時間
              //此時有消息,不能阻塞
                 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為正在使用的狀態(tài)
                  msg.markInUse();
                  // 返回msg
                  return msg;
                }
            } else {
             //沒有消息,會一直阻塞,直到被喚醒
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            //如果是退出狀態(tài),關閉消息隊列,返回null,拋棄MessageQueue
            if (mQuitting) {
                dispose();
                return null;
            }
            
// 下面的代碼是處理一些不緊急的任務
// 如果沒有符合條件的消息,會處理一些不緊急的任務
// 每次調用MessageQueue.next(),這些代碼只執(zhí)行一次
            
            if (pendingIdleHandlerCount < 0
                  && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount =mIdleHandlers.size();
            }
            
            // 當執(zhí)行過一次不緊急任務時,pendingIdleHandlerCount為
            //0,此時不會執(zhí)行下面的代碼,直接開始下一步循環(huán)
            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.
        //開始循環(huán)執(zhí)行所有的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只會在消息隊列阻塞之前執(zhí)行一次,執(zhí)行之后改標示設
        //置為0,之后就不會再執(zhí)行,一直到下一次調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.
        //當執(zhí)行了IdleHandler 的 處理之后,會消耗一段時間,這時候消息
        //隊列里的可能有消息已經到達可執(zhí)行時間,所以重置該變量回去重新檢
        //查消息隊列。
        nextPollTimeoutMillis = 0;
    }
}

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

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

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

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

msg.target.dispatchMessage(msg)

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

/**
 * 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不為空,則執(zhí)行handleCallback(Message),然后最終調用message.callback.run()。
  • 2.如果msg.callback為空,但mCallback不為空,則執(zhí)行mCallback.handleMessage(msg)。
  • 3.如果msg.callback 為空,且mCallback也為空,則執(zhí)行handleMessage()方法。

在大多數(shù)情況下,消息分發(fā)后的處理是第三種情況,即handleMessage(msg),這一般是通過復寫該方法的方式實現(xiàn)消息處理的業(yè)務邏輯。

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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容