Flutter app的入口函数就是`runApp()`。
~~~
void main() {
runApp(MyApp());
}
~~~
`runApp()`的函数体位于`widgets/binding.dart`。
~~~
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..attachRootWidget(app)
..scheduleWarmUpFrame();
}
~~~
ensureInitialized:确保各种Binding的初始化
attachRootWidget :为渲染树加入根节点
scheduleWarmUpFrame:渲染第一帧
## ensureInitialized
WidgetsFlutterBinding 实际上就是把Widget和Flutter绑定在一起的意思。
~~~
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
~~~
这个类继承自`BindingBase`并且混入(`Mixin`)了很多其他类,看名称都是不同功能的绑定。而静态函数`ensureInitialized()`所做的就是返回一个`WidgetsBinding.instance`单例。
混入的那些各种绑定类也都是继承自抽象类`BindingBase`的。
~~~
abstract class BindingBase {
BindingBase() {
...
initInstances();
...
}
...
ui.Window get window => ui.window;
}
~~~
关于抽象类`BindingBase`,你需要了解两个地方,一个是在其构造的时候会调用函数`initInstances()`。这个函数会由其子类,也就是上面说那些各种混入(Mixin)的绑定类各自实现,具体的初始化都是在其内部实现的。另一个就是`BindingBase`有一个`getter`,返回的是`window`。
我们需要重点关注的是`SchedulerBinding`,`RendererBinding`和`WidgetsBinding`。这3个是渲染流水线的重要存在。
### GestureBinding
手势绑定。
~~~
mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, HitTestTarget {
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onPointerDataPacket = _handlePointerDataPacket;
}
~~~
主要的事情就是给`window`设置了一个手势处理的回调函数。
### ServicesBinding
服务绑定
~~~
mixin ServicesBinding on BindingBase {
@override
void initInstances() {
super.initInstances();
_instance = this;
window
..onPlatformMessage = BinaryMessages.handlePlatformMessage;
initLicenses();
}
~~~
这个绑定主要是给`window`设置了处理Platform Message的回调。
### SchedulerBindind
调度绑定
~~~
mixin SchedulerBinding on BindingBase, ServicesBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onBeginFrame = _handleBeginFrame;
window.onDrawFrame = _handleDrawFrame;
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
}
~~~
这个绑定主要是给`window`设置了`onBeginFrame`和`onDrawFrame`的回调,回忆一下上一篇文章讲渲染流水线的时候,当Vsync信号到来的时候engine会回调Flutter的来启动渲染流程,这两个回调就是在`SchedulerBinding`管理的。
### PaintingBinding
绘制绑定
~~~
mixin PaintingBinding on BindingBase, ServicesBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
_imageCache = createImageCache();
}
~~~
这个绑定只是创建了个图片缓存
### SemanticsBinding
辅助功能绑定
~~~
mixin SemanticsBinding on BindingBase {
@override
void initInstances() {
super.initInstances();
_instance = this;
_accessibilityFeatures = window.accessibilityFeatures;
}
~~~
这个绑定管理辅助功能
### RendererBinding
渲染绑定
~~~
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
@override
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
window
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
_mouseTracker = _createMouseTracker();
}
~~~
#### 第一步:实例化PipelineOwner
实例化了一个`PipelineOwner`类。这个类负责管理驱动我们之前说的渲染流水线。
#### 第二步:设置window回调函数
给`window`设置了一系列回调函数,处理屏幕尺寸变化,亮度变化等。
#### 第三步:实例化了一个RenderView类
~~~
void initRenderView() {
assert(renderView == null);
renderView = RenderView(configuration: createViewConfiguration(), window: window);
renderView.scheduleInitialFrame();
}
~~~
这个函数实例化了一个`RenderView`类。`RenderView`继承自`RenderObject`。我们都知道Flutter框架中存在这一个渲染树(render tree)。。这个`RenderView`就是渲染树(render tree)的根节点。
#### 第四步:addPersistentFrameCallback
调用`addPersistentFrameCallback`添加了一个回调函数。渲染流水线的主要阶段都会在这个回调里启动。
### WidgetsBinding
组件绑定
~~~
mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
buildOwner.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
SystemChannels.system.setMessageHandler(_handleSystemMessage);
}
~~~
这个绑定的初始化先给`buildOwner`设置了个`onBuildScheduled`回调,还记得渲染绑定里初始化的时候实例化了一个`PipelineOwner`吗?这个`BuildOwner`是在组件绑定里实例化的。它主要负责管理Widget的重建,记住这两个"owner"。他们将会Flutter框架里的核心类。接着给`window`设置了两个回调,因为和渲染关系不大,就不细说了。最后设置`SystemChannels.navigation`和`SystemChannels.system`的消息处理函数。这两个回调一个是专门处理路由的,另一个是处理一些系统事件,比如剪贴板,震动反馈,系统音效等等。
## attachRootWidget
~~~
void attachRootWidget(Widget rootWidget) {
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget
).attachToRenderTree(buildOwner, renderViewElement);
}
~~~
~~~
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
/// Creates a bridge from a [RenderObject] to an [Element] tree.
///
/// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
RenderObjectToWidgetAdapter({
this.child,
this.container,
this.debugShortDescription
}) : super(key: GlobalObjectKey(container));
@override
RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
@override
RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;
...
}
~~~
1. 实例化 `RenderObjectToWidgetAdapter`,将它widget tree的根节点
2. createElement()返回的就是`RenderObjectToWidgetElement`,就是element tree的根节点了
3. `RendererBinding`的初始化的时候,我们得到了一个`RenderView`的实例 ,createRenderObject()返回的就是这个实例,就是render tree的根节点
`attachToRenderTree`做的事情属于我们之前说的渲染流水线的构建(Build)阶段,这时会根据我们自己的widget生成element tree和render tree。构建(Build)阶段完成以后,那自然是要进入布局(Layout)阶段和绘制(Paint)阶段了。
## scheduleWarmUpFrame
~~~
void scheduleWarmUpFrame() {
...
Timer.run(() {
...
handleBeginFrame(null);
...
});
Timer.run(() {
...
handleDrawFrame();
...
});
}
~~~
这个函数其实就调了两个函数,就是之前我们讲`window`的时候说的两个回调函数`onBeginFrame`和`onDrawFrame`,这里其实就是在具体执行这两个回调。最后渲染出来首帧场景送入engine显示到屏幕。