最近在看一篇文章的时候,有一段是这么描述的,咋感觉跟我理解的不太一样呢?为了看源码时少走一些弯路,我们就来看看WidgetsFlutterBinding是怎样使用mixin的。
那么, WidgetsFlutterBinding又是什么呢?WidgetsFlutterBinding是绑定widget 框架和Flutter 引擎的桥梁
void runApp(Widget app) {
final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
assert(binding.debugCheckZone('runApp'));
binding
..scheduleAttachRootWidget(binding.wrapWithDefaultView(app))
..scheduleWarmUpFrame();
}
我们可以看到,当flutter app启动的第一行代码就是初始化WidgetsFlutterBinding。
WidgetsFlutterBinding 继承了BindingBase,同时通过with扩展了很多binding,这些都是flutter的重要组成部分
GestureBinding 手势系统的binding,响应系统手势事件
SchedulerBinding 我们常说的帧,提供帧开始(onBeginFrame) ,绘制(onDrawFrame)的的时候的回调,监听刷新事件
ServicesBinding 监听平台消息,并发送到defaultBinaryMessenger,简单说就是主要处理原生和Flutter通信
PaintingBinding 绑定绘制库,用于处理图片缓存
SemanticsBinding 语义层和flutter 引擎的桥梁
RendererBinding 处理渲染树
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding._instance == null) {
WidgetsFlutterBinding();
}
return WidgetsBinding.instance;
}
}
可在WidgetsFlutterBinding.ensureInitialized()中,只是创建了WidgetsFlutterBinding()对象。那么这些binding是怎样完成初始化的呢?它们的执行顺序又是怎样的呢?
首先我们去flutter开发文档简单了解一下mixin,然后在《Flutter实战·第二版》这本书里有这么一句话:
如果多个mixin 中有同名方法,with 时,会默认使用最后面的 mixin 的,mixin 方法中可以通过 super 关键字调用之前 mixin 或类中的方法。
再回到WidgetsFlutterBinding代码,分析它们的执行顺序:
=>WidgetsFlutterBinding() //WidgetsFlutterBinding 继承自 BindingBase,执行BindingBase()
=>BindingBase() //BindingBase()中调用initInstances();
=>initInstances(); //被子类重写,多个binding中都有该方法的实现,执行最后with的mixin
=>WidgetsBinding.initInstances() //WidgetsBinding中的initInstances()被执行
=> super.initInstances(); //WidgetsBinding.initInstances()中第一行调用了super,则优先执行super
=>RendererBinding.initInstances(); //RendererBinding倒数第二个被with
...
依此类推
最终初始化顺序:
GestureBinding=>SchedulerBinding=>ServicesBinding=>PaintingBinding=>SemanticsBinding=>RendererBinding=>WidgetsBinding
现在我们已经知道,在WidgetsFlutterBinding这个主类中调用同名方法会遵循以上规则,那么我在其中一个mixin中调用了同名方法,又会怎样去执行呢?在我们查看手势源码GestureBinding的时候,就会遇到这个问题。
//GestureBinding中处理事件
void _handlePointerEventImmediately(PointerEvent event) {
HitTestResult? hitTestResult;
if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent || event is PointerPanZoomStartEvent) {
assert(!_hitTests.containsKey(event.pointer), 'Pointer of ${event.toString(minLevel: DiagnosticLevel.debug)} unexpectedly has a HitTestResult associated with it.');
hitTestResult = HitTestResult();
hitTest(hitTestResult, event.position); ///调用hitTest方法
}
//省略...
}
//GestureBinding中的hitTest
@override // from HitTestable
void hitTest(HitTestResult result, Offset position) {
result.add(HitTestEntry(this));
}
//RendererBinding中的hitTest
@override
void hitTest(HitTestResult result, Offset position) {
renderView.hitTest(result, position: position);
super.hitTest(result, position);
}
很多人在看到上方源码的时候,自然而然的就会想到执行的是GestureBinding中的hitTest,就不知道怎么往下看了。
而实际上,在mixin中调用同名方法,也会遵循主类的执行规则
主类WidgetsFlutterBinding 扩展的所有binding中,只有GestureBinding和RendererBinding实现了hitTest方法,而RendererBinding后with。因此,在GestureBinding中调用hitTest方法后,会先执行RendererBinding中的hitTest,RendererBinding.hitTest()中会调用 super.hitTest,才会执行到GestureBinding中的hitTest。