Flutter渲染过程的简介
使用Flutter开发有一段时间了,对Flutter的Framework层和Engine层有点模糊不清晰,趁着五一的假期,自己做个梳理;主要是想弄明白在Widget中使用setState后,Framework层和Engine层是怎么交互,从而让UI刷新的。
Flutter的渲染框架分为两层:
1)Framework层,负责渲染过程中的build、layout、paint、生成layer等环节;
2)Engine层,负责把Framwork层生成的layer组合生成纹理,然后通过OpenGL提交给GPU进行渲染;
Flutter的渲染过程可以大概分为下面几步:
1)Framework在setState后,调用接口通知Engine有UI需要更新;
2)Engine在下一个Vsync信号到达后,调用接口通知Framework层进行渲染;
3)Framework进行animations、build、layout、compositing、paint,生成layer提交给Engine层;
4)Engine层会把Layer进行组合生成纹理,通过OpenGL提交给GPU进行渲染;
一定要对上述的过程有个认识,否则看下面的代码会有点晕;大家可以看看参考一中的文章,写的很清晰。
Flutter渲染过程的源码分析
Framework和Engine之间的接口(胶水层)
sky_engine/lib/ui/window.dart
Class Window{//Framework和Engine之间的交互接口;
...
//Framework通过该接口通知Engine有UI需要更新,然后Engine会在Vsync信号到来后,调用下面的onBeginFrame和onDrawFrame
void scheduleFrame() native 'Window_scheduleFrame';
//Framework通过该接口将Layer信息交给Engine,Engine会在下一个Vsync来后将信息交给GPU进行渲染;
void render(Scene scene) native 'Window_render';
//当Engine收到Vsync信号后,调用onBeginFrame和onDrawFrame通知Framework进行绘制
VoidCallback get onDrawFrame => _onDrawFrame;
VoidCallback _onDrawFrame;
Zone _onDrawFrameZone;
set onDrawFrame(VoidCallback callback) {
_onDrawFrame = callback;
_onDrawFrameZone = Zone.current;
}
FrameCallback get onBeginFrame => _onBeginFrame;
FrameCallback _onBeginFrame;
Zone _onBeginFrameZone;
set onBeginFrame(FrameCallback callback) {
_onBeginFrame = callback;
_onBeginFrameZone = Zone.current;
}
....
}
从runApp开始
上述Window中的接口关联到Framework层,就是在runApp函数中通过WidgetsFlutterBinding设置上的;
flutter/lib/src/widgets/binding.dart
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
//注意这里的关键字with,这是dart的一种复用逻辑的方法
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
各个binding的具体解释可以看参考二的文章;
关于Mixin的理解可以看参考三的文章;
BindingBase
flutter/lib/src/foundation/binding.dart
abstract class BindingBase {
BindingBase() {
developer.Timeline.startSync('Framework initialization');
assert(!_debugInitialized);
initInstances();
assert(_debugInitialized);
assert(!_debugServiceExtensionsRegistered);
initServiceExtensions();
assert(_debugServiceExtensionsRegistered);
developer.postEvent('Flutter.FrameworkInitialization', {});
developer.Timeline.finishSync();
}
ui.Window get window => ui.window;//关联Window
}
SchedulerBinding
flutter/lib/src/scheduler/binding.dart,提供了window.onBeginFrame和window.onDrawFrame回调,监听刷新事件,绑定Framework绘制调度子系统。
mixin SchedulerBinding on BindingBase, ServicesBinding {
@override
void initInstances() {
...
}
void ensureVisualUpdate() {//有element rebuild的时候会调用到这里
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
void scheduleFrame() {
...
ensureFrameCallbacksRegistered();
window.scheduleFrame();//通知Engine有UI需要更新
_hasScheduledFrame = true;
}
@protected
void ensureFrameCallbacksRegistered() {
//设置Engine在Vsync信号来的时候通知framework进行渲染的接口
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
void addPersistentFrameCallback(FrameCallback callback) {
_persistentCallbacks.add(callback);
}
void _handleBeginFrame(Duration rawTimeStamp) {
...
handleBeginFrame(rawTimeStamp);
}
void handleBeginFrame(Duration rawTimeStamp) {
//执行_transientCallbacks中的回调
...
}
void _handleDrawFrame() {
...
handleDrawFrame();
}
void handleDrawFrame() {
//执行_persistentCallbacks和_postFrameCallbacks中的回调
...
}
RenderBinding
flutter/lib/src/rendering/binding.dart
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
@override
void initInstances() {
super.initInstances();
_instance = this;
...
//addPersistentFrameCallback会将drawFrame函数加入到_persistentCallbacks中,这样在Engine通知Framework渲染的时候会调用到drawFrame
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
}
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
}
@protected
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
//在compositeFrame中会调用_window.render(scene),也就是将组合好的layer提交给engine
renderView.compositeFrame(); // this sends the bits to the GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
}
}
WidgetsBinding
flutter/lib/src/widgets/binding.dart,
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
_buildOwner = BuildOwner();
//widget rebuild的时候会调用onBuildScheduled
buildOwner.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
}
void _handleBuildScheduled() {
...
ensureVisualUpdate();//逻辑定义在SchedulerBinding中
}
@override
void drawFrame() {
if (renderViewElement != null)
buildOwner.buildScope(renderViewElement);//将标记为dirty的element进行rebuild
super.drawFrame();
buildOwner.finalizeTree();
}
}
setState后,Framework层通知Engine层
framework.dart中,将需要rebuild的element标记为dirty,同时调用onBuildScheduled;
void setState(VoidCallback fn) {
_element.markNeedsBuild();
}
void markNeedsBuild() {
_dirty = true;
owner.scheduleBuildFor(this);
}
void scheduleBuildFor(Element element) {
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled();//就是WidgetsBinding初始化时设置的_handleBuildScheduled
}
_dirtyElements.add(element);
element._inDirtyList = true;
}
WidgetsBinding的初始化中,设置_handleBuildScheduled为owner的 onBuildScheduled
void _handleBuildScheduled() {
...
ensureVisualUpdate();//逻辑定义在SchedulerBinding中
}
SchedulerBinding中,会调用window的接口通知Engine有UI需要刷新
void ensureVisualUpdate() {//有element rebuild的时候会调用到这里
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
void scheduleFrame() {
...
ensureFrameCallbacksRegistered();
window.scheduleFrame();//通知Engine有UI需要更新
_hasScheduledFrame = true;
}
Vsync到来时,Engine通知Framework进行渲染、并把数据提交给Engine
在Vsync信号到来时,Engine会调用window.onBeginFrame和window.onDrawFrame,告诉Framework进行渲染 ;关键是,window.onBeginFrame和window.onDrawFrame是怎么设置上的呢?
SchedulerBinding中,每次Framework通知Engine有UI需要更新前,都会ensure window.onBeginFrame和window.onDrawFrame是否设置好,如果没有的话,会设置上;
void scheduleFrame() {
...
ensureFrameCallbacksRegistered();
window.scheduleFrame();//通知Engine有UI需要更新
_hasScheduledFrame = true;
}
@protected
void ensureFrameCallbacksRegistered() {//设置Engine在Vsync信号来的时候通知framework进行渲染的接口
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
_handleDrawFrame中执行的是执行_persistentCallbacks和_postFrameCallbacks中的回调;那么,_persistentCallbacks又是什么时候设置好的呢?
RenderBinding中,初始化的时候,会将drawFrame加入到_persistentCallbacks中
@override
void initInstances() {
super.initInstances();
...
//addPersistentFrameCallback会将drawFrame函数加入到_persistentCallbacks中,这样在Engine通知Framework渲染的时候会调用到drawFrame
addPersistentFrameCallback(_handlePersistentFrameCallback);
...
}
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
}
@protected
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
//在compositeFrame中会调用_window.render(scene),也就是将组合好的layer提交给engine
renderView.compositeFrame(); // this sends the bits to the GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
}
WidgetsBinding中,复写了drawFrame,所以会,先rebuild element,然后layout、composite、paint,再将组合好的layer提交给engine;
@override
void drawFrame() {
if (renderViewElement != null)
buildOwner.buildScope(renderViewElement);//将标记为dirty的element进行rebuild
super.drawFrame();
buildOwner.finalizeTree();
}