Android 同步屏障

86 阅读1分钟

前言

Handler消息分为同步消息、异步消息两类。Handler:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    // 是否时异步消息
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

Message:

// 判断是否时异步消息
public boolean isAsynchronous() {
    return (flags & FLAG_ASYNCHRONOUS) != 0;
}

同步消息和异步消息只有遇到同步屏障时,才会体现差异。

同步屏障

View绘制时,会在Looper中使用同步屏障,确保下一帧绘制完之前其他同步消息都暂不处理。异步消息不受同步屏障限制。

同步屏障工作原理

在MessageQueue.next()中

// MessageQueue.java
Message next() {  
    ...
    
    synchronized (this) {  
        // Try to retrieve the next message. Return if found.  
        final long now = SystemClock.uptimeMillis();  
        Message prevMsg = null;  
        Message msg = mMessages;  
        if (msg != null && msg.target == null) {  
            // 同步屏障,只处理异步消息
            do {  
                prevMsg = msg;  
                msg = msg.next;  
            } while (msg != null && !msg.isAsynchronous());  
        }  
        ...
        return msg;
        ...
    }  
    ...
}

View绘制的时候会使用同步屏障,ViewRootImpl:

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        // 设置同步屏障
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 移除同步屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        mChoreographer.removeCallbacks(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}

MessageQueue:

@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}

private int postSyncBarrier(long when) {
    // Enqueue a new sync barrier token.
    // We don't need to wake the queue because the purpose of a barrier is to stall it.
    synchronized (this) {
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.markInUse();
        msg.when = when;
        msg.arg1 = token;

        Message prev = null;
        Message p = mMessages;
        if (when != 0) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) { // invariant: p == prev.next
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

向MessageQueue中插入Message,这个Message的target没有赋值,target==null

总结:

  1. Handler中,Message分为同步消息、异步消息
  2. 同步屏障的先决条件msg.target==null
  3. 当出现同步屏障时,执行的是异步消息,同步消息会被过滤掉