RendererBinding
RendererBinding 顾名思义就是处理渲染相关的事情,它是flutter引擎与Render Tree之间的粘合剂,同时管理着多个独立的Render Tree,以及PipelineOwner的管理。
initInstances
- 创建
PipelineOwner - 设置
platformDispatcher的回调 - 添加
SchedulerBinding的持久帧回调
void initInstances() {
super.initInstances();
_instance = this;
_rootPipelineOwner = createRootPipelineOwner();
platformDispatcher
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged;
addPersistentFrameCallback(_handlePersistentFrameCallback);
......
rootPipelineOwner.attach(_manifold);
}
handleMetricsChanged
平台的指标数据(比如屏幕旋转、窗口大小改变时)发生改变,通知Flutter做出数据更新,并强制调用一帧。
[ViewConfiguration]保存着根渲染对象的布局约束
void handleMetricsChanged() {
bool forceFrame = false;
for (final RenderView view in renderViews) {
forceFrame = forceFrame || view.child != null;
view.configuration = createViewConfigurationFor(view);
}
if (forceFrame) {
scheduleForcedFrame();
}
}
drawFrame
drawFrame是RendererBinding最重要的一个方法了,启动PipelineOwner去生成新的一帧。
drawFrame由handleDrawFrame调用,而handleDrawFrame方法本身在需要布局和绘制一帧时由引擎自动调用。
这里再复习一下ScheduleBinding中handleBeginFrame和onDrawFrame的调用流程。
- 动画阶段:
handleBeginFrame方法已在PlatformDispatcher.onBeginFrame中注册,它会按注册顺序调用所有已在scheduleFrameCallback中注册的瞬时帧回调,其中包括所有驱动AnimationController对象的Ticker实例,这意味着所有活动Animation对象都会在此点执行tick; - 微任务:
handleBeginFrame返回后,所有由瞬时帧回调调度的微任务都会开始运行。这通常包括来自Ticker和AnimationController的 Future 回调,这些 Future 回调完成了此帧;
在handleBeginFrame之后,将调用platformDispatcher.onDrawFrame注册的 handleDrawFrame,该方法会调用所有持久帧回调,其中最值得注意的是drawFrame方法;
- 布局阶段:系统中所有已脏的
RenderObject都会被布局;
rootPipelineOwner.flushLayout()
- 合成位阶段:所有已脏的
RenderObject对象上的合成位都会被更新。
rootPipelineOwner.flushCompositingBits();
- 绘制阶段:系统中所有已脏的
RenderObject都会被重新绘制Layer tree;
rootPipelineOwner.flushPaint();
- 合成阶段:图层树转换为
Scene并发送到 GPU;
for (final RenderView renderView in renderViews) {
// this sends the bits to the GPU
renderView.compositeFrame();
}
- 语义阶段:系统中所有脏的
RenderObject的语义都会更新,这将生成语义树;
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
......
}
void drawFrame() {
rootPipelineOwner.flushLayout();
rootPipelineOwner.flushCompositingBits();
rootPipelineOwner.flushPaint();
if (sendFramesToEngine) {
for (final RenderView renderView in renderViews) {
renderView.compositeFrame(); // this sends the bits to the GPU
}
rootPipelineOwner.flushSemantics();
_firstFrameSent = true;
}
}