mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
我们可以看到正常情况下会执行scheduleFrameLocked方法
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, “Scheduling next frame on vsync.”);
}
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, “Scheduling next frame in " + (nextFrameTime - now) + " ms.”);
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
由于在4.1上是使用VSYNC信号的,所以就自然会调用scheduleVsyncLocked方法,会间接调用scheduleVsync方法
**
-
Schedules a single vertical sync pulse to be delivered when the next
-
display frame begins.
*/
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
- “receiver has already been disposed.”);
} else {
nativeScheduleVsync(mReceiverPtr);
}
}
注意:这里的注释说的很清楚了,当下一帧来临时准备一个要分发的垂直同步信号,啥意思呢?简单来说就是当调用了nativeScheduleVsync方法时,当屏幕需要刷新的时候,也就是每隔16.6ms会通过native的looper分发到java层,从而调用java的方法,那是哪个方法呢?
// Called from native code.
@SuppressWarnings(“unused”)
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
很明显是此方法
举个例子,比如屏幕显示的是第一帧,你在第一帧调用invalidate,其实并不是立即刷新的,而是在一帧会去注册一个Vsync(前提是这一帧cpu空闲情况下),当下一帧来临时也就是第二帧的时候会调用dispatchVsync此方法,当然这是一种比较简单的情况,复杂的等会说
那么来看一下调用的onVsync方法
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
// Ignore vsync from secondary display.
<