持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情
接下来会出三篇文章详细介绍,View视图如何经过一遍遍的流程渲染到界面上的,从
Activity的onResume(),经过Choreographer处理,经过FrameDisplayEventReceiver处理,最终触发View的measure、layout、draw三大流程,将视图绘制到界面上。
历史文章
从onResume()分析,ViewRootImpl在视图渲染中扮演什么角色?
概述
上篇文章讲了,ViewRootImpl类负责将视图通过WMS添加到真正的显示窗口中,并通过方法Choreographer.postCallback()方法添加渲染回调,触发后续的View的三大流程measure、layout、draw。
本篇文章就带你了解下Choreographer.postCallback()做了什么,如何触发后续View的三大渲染流程的。
从postCallback()方法开始分析
这个传入的mTraversalRunnable即Runnable对象是啥呢,看下:
关键的方法就是doTraversal(),这个方法最终会触发我们最终的View测量布局绘制流程,这个会放到另一篇文章中进行分析。
我们先一步步看下调用链:
最终调用到目标方法postCallbackDelayedInternal():
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
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);
}
}
}
-
首先将外部传入的Runnable即
action对象设置到mCallbackQueues这个数组中,记住这个数组,后面会有大用; -
delayMillis这个参数值传入的为0,所以判断条件dueTime <= now成立,会走到方法scheduleFrameLocked()中:
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
}
}
}
我们看下这段代码逻辑,USE_VSYNC标识是否监听使用垂直脉冲信号,Android5.0之后这个值都是为true的;
另外isRunningOnLooperThreadLocked()方法就是判断当前线程是否和创建ViewRootImpl的线程是同一个,如果不是就通过Handler切换到创建线程中执行。最终都会调用到方法scheduleVsyncLocked()。
mDisplayEventReceiver是一个FrameDisplayEventReceiver类型对象,其中FrameDisplayEventReceiver继承了抽象类DisplayEventReceiver,所以最终这个方法scheduleVsync()会走到DisplayEventReceiver类中 :
nativeScheduleVsync()是一个native方法,这个方法最终会注册接收底层的垂直脉冲信号的,一般为16ms发送一次。
既然注册了,那监听到后的回调方法肯定也是有的,那就是DisplayEventReceiver.onVsync()方法:
可以看到这个方法的注释中也是有写到,当底层的垂直脉冲信号到来时,这个方法就会被调用。
FrameDisplayEventReceiver子类重写了onVsync()方法:
关键的代码就是在红框中,发送一个异步消息(提高渲染相关任务执行的优先级),并将当前的FrameDisplayEventReceiver对象作为Runnable对象传入到Handler中分发执行。
FrameDisplayEventReceiver实现了Runnable接口,我们看下其实现的run方法:
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
doFrame()方法就是非常关键的一个核心方法了,这个方法就会从上面添加的数组mCallbackQueues中取出视图渲染的回调开始执行,具体的详细执行逻辑我们放到下一篇也是最后一篇文章进行分析。
总结
本篇文章分析了Choreographer在视图渲染中扮演的角色:
-
添加视图渲染回调到数组中;
-
注册接收底层垂直脉冲信号;
-
接受脉冲信号触发java层开始视图的真正渲染;
希望本篇文章能给你带来帮助,感谢阅读!!