0%

屏幕刷新机制

requestLayout

view.requestLayout 最终会调用 ViewRootImpl.requestLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread(); // 检查线程是否是 ViewRootImpl 实例化的线程
mLayoutRequested = true;
scheduleTraversals();
}
}

void scheduleTraversals() {
// mTraversalScheduled 标记位,避免短时间多次调用requestLayout重复刷新
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 添加一个同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过 Choreographer 添加一个 Vsync 回调
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}

final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}

void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

// 开始 measure layout draw 三步走
performTraversals();
}
}

这个 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); 这个操作会在 LooperQueue 中添加一个同步屏障,阻断同步 message(普通 message )的执行。
(异步 message 能正常执行)
这里主要是为了保证在 Vync 到来时,这个 message 能够快速响应,保证在 Vync 到来的最初时刻就开始绘制,从而保证 UI 的绘制和 Vync 的周期是协调的。

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 添加一个 Vsync 回调。在 Vsync 信号到来时执行 mTraversalRunnable 。

Choreographer

Choreographer 是用来监听 Vsync 信号的一个类。 在刷新UI时主要有两步。

添加一个 vsync 信号的回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
// 这里 mCallbackQueues 是多个事件的队列
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
// 延时做刷新,最终也会走 scheduleFrameLocked
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}

private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
// 判断是不是在 ViewRootImpl 实例化时的线程
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
// 如果不是,用一个 Handler 切换线程
// 发送一个异步消息,并且放置在队列最前方
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
...
}
}
}

private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}

public void scheduleVsync() {
if (mReceiverPtr == 0) {
...
} else {
// 调用 native 方法请求一个 vsync 回调
nativeScheduleVsync(mReceiverPtr);
}
}

处理 vsync 回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 在 Choreographer 的构造方法里实例化 DisplayEventReceiver
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mHandler = new FrameHandler(looper);
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
mLastFrameTimeNanos = Long.MIN_VALUE;

mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());

mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;

public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}

@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
long now = System.nanoTime();
if (timestampNanos > now) {
timestampNanos = now;
}

mTimestampNanos = timestampNanos;
mFrame = frame;
// 发送一个异步消息,注意,这里没有放置到消息队列最前端
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

@Override
public void run() {
doFrame(mTimestampNanos, mFrame);
}
}

void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}

long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
// 当前时间 - vsync回调到来时间 = 主线程message耗时
final long jitterNanos = startNanos - frameTimeNanos;
// 当超过了屏幕一帧刷新时间 16ms
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
// 当跳过的帧超过一定程度
}
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
frameTimeNanos = startNanos - lastFrameOffset;
}

mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

// 处理屏幕刷新的回调,这里会调用 ViewRootImpl.TraversalRunnable
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} ...
}