我正在参加「掘金·启航计划」
runApp入口
在Flutter的main函数创建根组件作为入参初始化了WidgetsFlutterBinding。
WidgetsFlutterBinding
WidgetsFlutterBinding是一个特殊类继承了BindingBase又混入了各种Binding。而混入with也是Dart比较特殊的语法糖同时也是WidgetsFlutterBinding类特别之处。
WidgetsFlutterBinding实现比较简单只做了初始化功能,实例化单例对象WidgetsBinding。(暂且先不关心它)先分别介绍一下每个Binding的职责。
WidgetsBinding
initInstances初始化函数大致可知WidgetsBinding主要职责是负责脏节点刷新以及平台的本地化、特性变化和帧刷新等监听工作,脏节点组件更新由BuildOwner负责完成。
RendererBinding
initInstances初始化函数中创建了PipelineOwner、RenderView,其主要职责是负责Flutter的UI渲染工作,PipelineOwner并是负责渲染的重要类。
此外
RenderingFlutterBinding类是类似WidgetsFlutterBinding带有初始化方法ensureInitialized实例化对象。
SemanticsBinding
SemanticsBinding主要处理平台上辅助服务事件,所负责职责比较少。
PaintingBinding
PaintingBinding主要职责管理图片缓存和着色器预热,分别由ImageCache和ShaderWarmUp管理。
ServicesBinding
ServicesBinding主要职责创建二进制通信服务、平台软键盘功能、平台系统消息通信和生命周期以及平台插件方法等注册。
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage)负责生命周期SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object))负责系统信息监听(例如低内存警告memoryPressure)_initKeyboard()负责软硬键盘输入信息SystemChannels.platform.setMethodCallHandler(_handlePlatformMessage)负责平台方法调用
SchedulerBinding
SchedulerBinding负责任务调度处理各种类型任务调度时机,之前讲到的三辆马车运作就是在该类中实现的。其主要能力是和平台帧交互,调度平台帧等待平台的开始帧和绘制帧来驱动三辆马车运作起来从而达到刷新UI和驱动任务的作用。
_timingsCallbacks用于检测GPU耗时检测handleAppLifecycleStateChanged控制帧状态是否可用(后台情况下不刷新)_persistentCallbacks、_postFrameCallbacks以及_transientCallbacks三个回调分别代表瞬时回调、帧结束回调和动画回调。
GestureBinding
GestureBinding负责手势操作处理对Flutter事件分发管理。
_handlePointerDataPacket接受平台发起事件数据包_pendingPointerEvents是事件数据包队列_flushPointerEventQueue循环_pendingPointerEvents队列,只要队列不为空并做处理handlePointerEvent会通过_handlePointerEventImmediately处理指针事件PointerEvent得到HitTestResult结果- 通过
dispatchEvent将HitTestResult结果分发。
PS:事件分发也是
Flutter开发中重要一环,后续可以单独展开说说
mixin & with & on
在WidgetsFlutterBinding类实现上可看到with各种xxxBinding,此外其他Binding是mixin且又on其他Binding,这就是dart特殊语法糖:混入类。
Mixin是一种在多个类层次结构中重用类代码的方法。Mixin支持混入多个对象。- 用
Mixin修饰对象不能有构造函数,因此无法直接实例化对象。(除非该对象是Class就不能是Mixin) on关键字主要为了限制Mixin,例如Mixin类型B是on了A类,若C希望withB就必须继承A类;Mixin类型B是on了Mixin类型A,若C希望withB同样需要Mixin类型A并且A必须在B的前面
如下是mixin、on、with使用场景实操来演示最终结果展示。
class A {
void todo() {
print("<> todo A");
}
}
mixin AA on A {
@override
void todo() {
super.todo();
print("<> todo AA");
}
void todo2(){
print("<> todo2 AA");
}
}
mixin AAA on A{
void todo2(){
print("<> todo2 AAA");
}
@override
void todo() {
super.todo();
print("<> todo AAA");
}
}
mixin AAAS on AAA{
@override
void todo2(){
super.todo();
print("<> todo2 AAAS");
}
}
demo1
BB继承A并且with了AAA和AA当执行todo2()时执行AA的todo2()。由于with特性是找到最远混入对象因此执行输出是"<> todo2 AA",若with是 AA,AAA那么执行方法就变成是AAA的todo2()输出变为"<> todo2 AAA"。
class BB extends A with AAA,AA {
@override
void todo() {
super.todo();
print("<> todo BB");
}
}
void main(){
BB bb = BB();
bb.todo2();//<> todo2 AA
}
因此可以知with并不是继承(可能容易理解为继承关系)with的每个对象同一个方法名是相互隔离,而被with对象调用了哪个方法名取决于with的最后一个是哪个。
demo2
CC直接with到AAAS是非法的,因为AAAS是on了AAA,且AAA还on了A。
class CC with AAAS{
void todo() {
super.todo();
print("<> todo CC");
}
}
因此
CC需要继承A然后依次with到AAA和AAAS(顺序不能乱),另外CC也可以不继承A同样采用with也是可以的,位置同样重要必须在AAA和AAAS前面。
class CC extends A with AAA,AAAS{
void todo() {
super.todo();
print("<> todo CC");
}
}
回顾
再看Flutter的Binding设计就很好运用了with思路,每个Binding都有各自职责虽然每个职责又无法做到绝对独立,但每个Binding存在着关联系,如果设计采用继承关系反而会将每个Binding捆绑,抽象方法过度实现等问题。而采用with可以隔离每个Binding又能互相调用而实现整个系统运作。