if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance!;
}
}
WidgetsFlutterBinding类继承自BindingBase并且混入[mixin]了很多其他Binding类,看名称都是绑定各种不同的功能;
BindingBase,上面的各个mixin Binding类都是继承自它,各个mixin类都重写了initInstances()方法,并且调用了super.initInstances(),所以他们所有的initInstans()方法都会被串行顺序执行。如果对mixin机制不是很理解可以先看看”小白都能看懂的关于Mixins机制的理解“。最终FlutterWidgetBinding()初始化的逻辑为:
WidgetsFlutterBinding经过mixin依赖,实现了所有的Binding类的功能,下面逐一大概介绍一下每个Binding的作用:
GestureBinding
:提供了window.onPointerDataPacket
的回调,绑定Fragmework子系统,是Framework事件模型与底层事件的绑定入口。
ServicesBinding
:提供了window.onPlatformMessage
回调,用于绑定平台消息通道(messagechannel
),主要处理原生和Flutter之间的通信。
SchedulerBinding
:提供了window.onBeginFrame和window.onDrawFrame回调,监听刷新事件,绑定Framework绘制调度子系统
PaintingBinding
:绑定绘制库,主要用于处理图片缓存。
SematicsBinding
:语义化层与Flutter engine的桥梁,主要是辅助功能的底层支持。
RenderBinding
:提供了window.onMetricsChange、window.onTextScaleFactorChanged等回调。它是渲染树与Flutter engine的桥梁。
WidgetsBinding
:提供了window.onLocaleChanged,onBuildScheduled等回调。它是Flutter widget层与engine的桥梁。
很明显,可以看到Window
类提供了各种平台的回调方法,正是我们Flutter Framework连接宿主操作系统的接口。我们来大致看下源码:
class Window {
// 当前设备的DPI,即一个逻辑像素显示多少物理像素,数字越大,显示效果就越精细保真。
// DPI是设备屏幕的固件属性,如Nexus 6的屏幕DPI为3.5
double get devicePixelRatio => _devicePixelRatio;
// Flutter UI绘制区域的大小
Size get physicalSize => _physicalSize;
// 当前系统默认的语言Locale
Locale get locale;
// 当前系统字体缩放比例。
double get textScaleFactor => _textScaleFactor;
// 当绘制区域大小改变回调
VoidCallback get onMetricsChanged => _onMetricsChanged;
// Locale发生变化回调
VoidCallback get onLocaleChanged => _onLocaleChanged;
// 系统字体缩放变化回调
VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged;
// 绘制前回调,一般会受显示器的垂直同步信号VSync驱动,当屏幕刷新时就会被调用
FrameCallback get onBeginFrame => _onBeginFrame;
// 绘制回调
VoidCallback get onDrawFrame => _onDrawFrame;
// 点击或指针事件回调
PointerDataPacketCallback get onPointerDataPacket => _onPointerDataPacket;
// 调度Frame,该方法执行后,onBeginFrame和onDrawFrame将紧接着会在合适时机被调用,
// 此方法会直接调用Flutter engine的Window_scheduleFrame方法
void scheduleF
rame() native ‘Window_scheduleFrame’;
// 更新应用在GPU上的渲染,此方法会直接调用Flutter engine的Window_render方法
void render(Scene scene) native ‘Window_render’;
// 发送平台消息
void sendPlatformMessage(String name,
ByteData data,
PlatformMessageResponseCallback callback) ;
// 平台通道消息处理回调
PlatformMessageCallback get onPlatformMessage => _onPlatformMessage;
… //其它属性及回调
}
Window
类包含了当前设备和系统的一些信息以及Flutter Engine的一些回调。通过这些Binding 监听Window对象的一些事件,然后将这些事件按照Framework的模型包装,抽象再分发。
2、scheduleAttachRootWidget
WidgetsFlutterBinding初始化之后,接着会调用WidgetsBinding.attachRootWidget
方法,该方法负责将根Widget添加到RenderView
上,
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter(
container: renderView,
debugShortDescription: ‘[root]’,
child: rootWidget,
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement?);
}
注意:
代码中的renderView
是一个RenderObject
,它渲染树的根
renderViewElement
是renderView对应的Element对象,可见该方法主要完成根widget到根RenderObject再到跟Element的整个关联过程。
再来看看attachToRenderTree源码实现:
/// Inflate this widget and actually set the resulting [RenderObject] as the
/// child of [container].
///
/// If element
is null, this function will create a new element. Otherwise,
/// the given element will have an update scheduled to switch to this widget.
///
/// Used by [runApp] to bootstrap applications.
RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? element ]) {
if (element == null) {
owner.lockState(() {
element = createElement();
assert(element != null);
element!.assignOwner(owner);
});
owner.buildScope(element!, () {
element!.mount(null, null);
});
// This is most likely the first time the framework is ready to produce
// a frame. Ensure that we are asked for one.
SchedulerBinding.instance!.ensureVisualUpdate();
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element!;
}
first time the framework is ready to produce
// a frame. Ensure that we are asked for one.
SchedulerBinding.instance!.ensureVisualUpdate();
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element!;
}