持续创作,加速成长!这是我参与「掘金日新计划 · 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层开始视图的真正渲染;
希望本篇文章能给你带来帮助,感谢阅读!!