天天看點

Android Handler 同步屏障

簡單了解

異步消息相比同步消息要優先執行,好比 :

當一堆人在排隊進周傑倫演唱會時候,周傑倫來了,就通知保安,周傑倫來了,于是優先給周傑倫進去,等周傑倫進去後,其他人再按順序進去

專業解釋就是:

當開啟了同步障礙時,Looper在擷取下一個要執行的消息時,會在連結清單中尋找第一個要執行的異步消息,如果沒有找到異步消息,就讓目前線程沉睡。

nativeWake()方法和nativePollOnce()方法采用了Linux的epoll機制,其中nativePollOnce()的第二個值,當它是-1時會一直沉睡,直到被主動喚醒為止,當它是0時不會沉睡,當它是大于0的值時會沉睡傳入的值那麼多的毫秒時間。epoll機制實質上是讓CPU沉睡,來保障目前線程一直在運作而不中斷或者卡死,這也是Looper#loop()死循環為什麼不會導緻住縣城ANR的根本原因。

Android 中異步消息應用場景:

在ViewRootImpl.java中有使用它:
void scheduleTraversals() {
  if (!mTraversalScheduled) {

    mTraversalScheduled = true;
    // 開啟目前Handler的同步屏障
    mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    // 發送一條異步消息
    mChoreographer.postCallback(..., mTraversalRunnable, null);

    if (!mUnbufferedInputDispatch) {
        cheduleConsumeBatchedInput();
    }

    notifyRendererOfFramePending();
    pokeDrawLockIfNeeded();
  }
}      

這裡的 ​

​Handler​

​​ 使用的是主線程的 ​

​Looper​

​​,是以這裡會阻斷主線程 ​

​Looper​

​​ 的其他同步消息,在​

​ViewRootImpl​

​​ 和 ​

​Choreographer​

​​ 中多次使用到了異步消息,以完成 ​

​View​

​ 的整個繪制流程。

停止一個 HandlerThread

while (true) {
            Message msg = queue.next(); // might block
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
 
                long wallStart = 0;
                long threadStart = 0;
 
                // 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);
                    wallStart = SystemClock.currentTimeMicro();
                    threadStart = SystemClock.currentThreadTimeMicro();
                }
 
                msg.target.dispatchMessage(msg);      
public void quit() {
        Message msg = Message.obtain();
        // NOTE: By enqueueing directly into the message queue, the
        // message is left with a null target.  This is how we know it is
        // a quit message.
        mQueue.enqueueMessage(msg, 0);
    }      
mHandlerThread.getLooper().quit();      

參考連結

  • ​​Android築基——可視化方式了解 Handler 的同步屏障機制​​
  • ​​每日問答 Handler應該是大家再熟悉不過的類了,那麼其中有個同步屏障機制,你了解多少呢?​​
  • ​​Android Handler 源碼分析​​
  • ​​揭秘 Android 消息機制之同步屏障:target==null ?​​
  • ​​終止Android中HandlerThread的方法​​
  • ​​Android消息機制Message的target==null的黑科技​​