说起启动那必须从main方法开始呀
void main() => runApp(MyApp());
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
runApp的代码很简单,传递一个Widget参数,然后执行了三行代码,三行代码代表了Flutter App启动的主要三个流程:
- binding初始化(ensureInitialized)
- 绑定根节点(scheduleAttachRootWidget)
- 绘制热身帧(scheduleWarmUpFrame)
binding初始化(ensureInitialized)
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
mixin我们前面已经介绍过了,不难发现 WidgetsFlutterBinding 单例过程其实也是对7个mixin的binding的初始化 。
WidgetsFlutterBinding继承了BindingBase,在调用自己的构造器之前会先先执行了父类BindingBase构造函数。
BindingBase() {
developer.Timeline.startSync('Framework initialization');
assert(!_debugInitialized);
initInstances();
assert(_debugInitialized);
assert(!_debugServiceExtensionsRegistered);
initServiceExtensions();
assert(_debugServiceExtensionsRegistered);
developer.postEvent('Flutter.FrameworkInitialization', {});
developer.Timeline.finishSync();
}
WidgetsBinding 覆盖了前面的 binding 的 initInstances(),所以 WidgetsBinding 的 initInstances() 会首先被调用,而 WidgetsBinding 的 initInstances 函数中先通过 super 向上调用 initInstances ,根据mixin的特性 执行顺序: initInstances 的执行顺序依次是:BindingBase -> GestureBinding -> SchedulerBinding -> ServicesBinding -> PaintingBinding -> SemanticsBinding -> RendererBinding -> WidgetsBinding,从而依次完成各个 Binding 的初始化相关工作。
RendererBinding
mixin RendererBinding on BindingBase,
{
@override
void initInstance() {
super.initInstance();
_pipelineOwner = PipelineOwner(
……………
);
……………
initRenderView(){
renderView = RenderView(
configuration:createViewConfiguration(),
window:window
);
……………
}
}
}
}
PipelineOwner是渲染管道,它在widget渲染的阶段有重要的作用,具体的会在后续的渲染绘制会着重分析.
RenderView 就是我们屏幕真实显示的那个View,Flutter是单页面的UI框架,renderView就是这个时间点被初始化出来的。它是Render tree 的根节点,同时将当前设备的物理屏幕信息配置上。
SemanticsBinding
渲染辅助类绑定,主要负责关联语义树与Flutter Engine。Flutter维护了一个 semantic tree(语义树),页面构建的时候会根据各Widget的语义描述构建一棵 semantic tree。如在Image组件中配置 semanticLabel 语义内容,用户在IOS/Android手机开启无障碍功能时,触摸到该 Image 时通过语义树查找到对应的语义描述交给Flutter Engine,实现读屏等功能。对应Semantics widget,给子Widget定义语义,一些安卓自动化无法识别flutter上的widget,通过Semantics 定义语义就可以识别出来了
PaintingBinding
监听系统字体变化事件
ServicesBinding
@override
void initInstances() {
super.initInstances();
_instance = this;
// 构建一个用于platform与flutter层通信的 BinaryMessenger
_defaultBinaryMessenger = createBinaryMessenger();
// 设置window监听回调,处理platform发送的消息
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
initLicenses();
// 设置处理platform发送的系统消息的 Handler
SystemChannels.system.setMessageHandler(handleSystemMessage);
// 设置AppLifecycleState生命周期回调
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
// AppLifecycleState 为 resumed 和 inactive 时才允许响应Vsync信号进行绘制
readInitialLifecycleStateFromNativeWindow();
}
ServicesBinding的初始化的工作主要是两个:
- platform与flutter层通信相关服务的初始化(比如读取asset内的资源就是通过defaultBinaryMessenger 也是内部默认的channel使用的消息对象 )
- 注册监听了flutter app的生命周期变化事件,根据生命周期状态决定是否允许发起绘制任务
SchedulerBinding
绘制调度绑定,绘制渲染流程会详细分析,也可关注文后的绘制流程时序图
GestureBinding
手势事件绑定,主要处理触屏幕指针事件的分发以及事件最终回调处理。
绑定根节点(scheduleAttachRootWidget)
@protected
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
// 将传入的Widget绑定RenderView根节点上
attachRootWidget(rootWidget);
});
}
attachRootWidget源码:
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement);
}
先是通过传入的 rootWidget 及 RenderView 实例化了一个RenderObjectToWidgetAdapter对象,而RenderObjectToWidgetAdapter是继承自RenderObjectWidget,即创建了Widget树的根节点。继续调用 attachToRenderTree:
RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement element ]) {
if (element == null) {
owner.lockState(() {
// 创建了一个RenderObjectToWidgetElement实例作为element tree的根节点
element = createElement();
assert(element != null);
// 绑定BuildOwner
element.assignOwner(owner);
});
// 标记需要构建的element,并rebuild
owner.buildScope(element, () {
element.mount(null, null);
});
SchedulerBinding.instance.ensureVisualUpdate();
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element;
}
@override
void mount(Element parent, dynamic newSlot){
………
_rebuild();
}
void _rebuild(){
………
_child = updateChild(_child, widget.child. _rootChildSlot);
………
}
}
@override
RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this);
attachToRenderTree 中通过 createElement() 创建了一个RenderObjectToWidgetElement 实例作为 element tree 的根节点,并绑定BuildOwner,通过 BuildOwner 构建需要构建的 element。
在mount函数这里会触发_rebuild();在_rebuild()里面我们看到了updateChild,updateChildl里有调用inflateWidget方法,inflateWidget这个函数,在这个函数里面就会触发StatelessWidget和StatefulWidget的 createElement去创建element ,element又会去调用对应类的mount函数,经过一系列的流程之后,又会回到inflateWidget这个函数中,再次触发新的mount函数,形成一个层层调用,不断创建parentElement到childElement的过程,这个过程完成了element tree的构建。
绘制热身帧(scheduleWarmUpFrame)
void scheduleWarmUpFrame() {
if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)
return;
_warmUpFrame = true;
Timeline.startSync('Warm-up frame');
final bool hadScheduledFrame = _hasScheduledFrame;
Timer.run(() {
assert(_warmUpFrame);
handleBeginFrame(null);
});
Timer.run(() {
assert(_warmUpFrame);
handleDrawFrame();
resetEpoch();
_warmUpFrame = false;
if (hadScheduledFrame)
scheduleFrame();
});
lockEvents(() async {
await endOfFrame;
Timeline.finishSync();
});
}
热身帧是通过handleBeginFrame、handleDrawFrame这两个回调来进行绘制流程。handleBeginFrame处理动画相关逻辑,动画回调后并不立即执行动画,而是改变了animation.value,并调用setSate()来发起绘制请求。动画的过程就是在 Vsync 信号到来时根据动画进度计算出对应的 value,而对应的 Widget 也会随着 animation.value 的变化而重建,从而形成动画,和Android的属性动画原理差不多。handleBeginFrame处理完后,会优先处理microTask任务队列。然后才是event Task,window.onDrawFrame(),对应SchedulerBinding.handleDrawFrame()。(Timer任务会加入到event queue,flutter的事件处理机制是优先处理 micro queue 中任务)
void handleDrawFrame() {
assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
Timeline.finishSync(); // end the "Animate" phase
try {
// 处理Persistent类型回调,主要包括build\layout\draw流程
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
// 注释1
_invokeFrameCallback(callback, _currentFrameTimeStamp);
// 处理Post-Frame回调,主要是状态清理,准备调度下一帧绘制请求
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List localPostFrameCallbacks =
List.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp);
} finally {
// 处理完成,设置状态为idle
_schedulerPhase = SchedulerPhase.idle;
Timeline.finishSync(); // end the Frame
assert(() {
if (debugPrintEndFrameBanner)
debugPrint('▀' * _debugBanner.length);
_debugBanner = null;
return true;
}());
_currentFrameTimeStamp = null;
}
}
// RendererBinding
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
_mouseTracker.schedulePostFrameCheck();
}
void drawFrame() {
assert(renderView != null);
// 布局
pipelineOwner.flushLayout();
// 更新 RenderObject 中需要绘制的内容
pipelineOwner.flushCompositingBits();
// 绘制
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
// 产生这一帧的数据Scene,由window.render交给Engine,最终显示到屏幕(发送数据到GPU)。
renderView.compositeFrame();
// 将语义树发送到操作系统
pipelineOwner.flushSemantics();
_firstFrameSent = true;
}
}
// WidgetsBinding
void drawFrame() {
...
try {
if (renderViewElement != null)
//调用BuildOwner.buildScope开始构建
buildOwner.buildScope(renderViewElement);
//调用RendererBinding.drawFrame,开始布局、绘制阶段。
super.drawFrame();
//从element tree中移除不需要的element,unmount
buildOwner.finalizeTree();
} finally {
...
}
}
SchedulerBinding.scheduleWarmUpFrame
-> SchedulerBinding.handleBeginFrame 处理动画
-> SchedulerBinding.handleDrawFrame
-----> WidgetBinding.drawFrame 通过 buildOwner 构建组件
-----> RendererBinding.drawFrame 通过 pipelineOwner 完成组件布局和绘制
-----> renderView.compositeFrame 发送 Scene 到GPU
欢迎拍砖,交流!