天天看点

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的黑科技​​