溧阳网站建设哪家好,经典重庆论坛,vps做网站教程,上门做指甲哪个网站一#xff0c;Mixins1#xff0c;定义#xff1a;Mixins 是一种在多个类层次结构中重用类代码的方法。个人理解#xff1a;就是一个类#xff0c;这个类有一些方法#xff0c;其他类可以在不继承这个类的情况下使用这个类的方法。2#xff0c;几个关键词#xff08;1Mixins1定义Mixins 是一种在多个类层次结构中重用类代码的方法。个人理解就是一个类这个类有一些方法其他类可以在不继承这个类的情况下使用这个类的方法。2几个关键词1mixin:一般使用mixin关键字定义可以混合的类2with:使用混合时用with关键字1on:添加限定条件如下意思是这个类只能被on的类或者子类混合3现在有这个情况class A{A(){print(A constructor);}log() print(A log);
}
mixin AA on A{log() {print(AA log);}
}
mixin AB on A{overridelog() {super.log();print(AB log);}
}
//C是A的子类所以可以混合AA和AB
class C extends A with AA,AB{overridelog() {super.log();print(C log);}
}类C继承类A并且混合了AA和AB这几个类都有log方法现在执行C().log()会输出什么答案是I/flutter (16574): A constructor
I/flutter (16574): AA log
I/flutter (16574): AB log
I/flutter (16574): C log因为混合类时进行混合的多个类是线性的所以他们的共有方法不会冲突会优先调用后面混合的类的方法所以混合的顺序决定了混合时相同的方法的处理逻辑。像这个例子执行的方法肯定是C.log但因为super.log()所以会调用AB.log,AA.log,因为AA.log没有super,所以没有调用A.log。mixin的类不能有构造函数,不能继承其他类因为mixin机制语义上是向一个类混入其他类的方法或者成员变量,使得我们可以在混合类中访问到混入类的方法或者属性。而混入其他类的构造函数实际上是没有意义的,因为不会有人手动去调用这个混入类的构造函数。二runAPP()从这儿开始执行runApp(const MyApp());void runApp(Widget app) {//1,初始化//2绑定根节点//3绘制热身帧WidgetsFlutterBinding.ensureInitialized()..scheduleAttachRootWidget(app)..scheduleWarmUpFrame();
}2.1初始化2.1.1初始化函数看下初始化函数这儿是WidgetsFlutterBinding的单例过程因为要确保flutter完成初始化并且只完成一次这儿调用了自己的构造器static WidgetsBinding ensureInitialized() {if (WidgetsBinding._instance null)WidgetsFlutterBinding();return WidgetsBinding.instance;
}对于WidgetsFlutterBinding这个类继承了BindingBase并且混入了7个类class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding{因为WidgetsFlutterBinding继承BindingBase在调用构造方法前会先调用BindingBase的构造方法所以看下父类BindingBase的构造方法BindingBase() {developer.Timeline.startSync(Framework initialization);//注意这个方法其他七个混入的类都有//绑定初始化initInstances();//在绑定初始化完成后进行服务初始化initServiceExtensions();developer.postEvent(Flutter.FrameworkInitialization, String, String{});developer.Timeline.finishSync();
}因为initInstances()方法其他几个混入的类都有所以WidgetsBinding 会覆盖前面混入的 initInstances()所以 WidgetsBinding 的 initInstances() 会首先被调用而 WidgetsBinding 还有其他几个混入的类的 initInstances 函数中都执行了super.initInstances();所以根据mixin的特性 initInstances 的执行顺序依次是BindingBase - GestureBinding - SchedulerBinding - ServicesBinding - PaintingBinding - SemanticsBinding - RendererBinding - WidgetsBinding从而依次完成各个 Binding 的初始化相关工作。2.1.2七个Bindding1GestureBinding手势事件绑定主要处理触屏幕指针事件的分发以及事件最终回调处理。2SchedulerBinding绘制调度绑定,和绘制渲染流程有关。3ServicesBinding1platform与flutter层通信相关服务的初始化接收MethodChannel和SystemChannels传递过来的消息2注册监听了flutter app的生命周期变化事件根据生命周期状态决定是否允许发起绘制任务4PaintingBinding和图片缓存有关。5SemanticsBinding语义相关的初始化主要就是描述应用程序中的UI信息用于读屏使用。6RendererBinding1初始化了渲染管道PipelineOwner和RenderView这就是我们屏幕真实显示的那个ViewFlutter是单页面的UI框架renderView就是这个时间点被初始化出来的。2注意初始化方法中把renderView挂载到pipelineOwner.rootNode上RenderView是RenderObject的子类renderView其实是Render tree 的根节点后续会讲到。7WidgetsBinding1初始化了一个BuildOwner对象它主要是执行widget tree的build任务2执行了一些window的回调。2.2绑定根节点2.2.1接下来看绑定根节点的方法scheduleAttachRootWidget()void scheduleAttachRootWidget(Widget rootWidget) {Timer.run(() {//传入了rootWidget这个rootWidget就是我们构建的MyApp()这个方法主要是绑定根节点attachRootWidget(rootWidget);});
}/// 创建树的根节点
/// 这个方法主要是将根widget和根element和根renderObject关联起来
/// 并将唯一的BuildOwner对象引用作为根对象的持有对象通过继承关系层层传递
void attachRootWidget(Widget rootWidget) {final bool isBootstrapFrame renderViewElement null;_readyToProduceFrames true;//1初始化了一个RenderObjectToWidgetAdapter对象//RenderObjectToWidgetAdapter继承RenderObjectWidget所以本质是一个widget可以说创建了widget树的根节点//调用attachToRenderTree_renderViewElement RenderObjectToWidgetAdapterRenderBox(container: renderView,//之前介绍的在RendererBinding初始化的对象也是renderObject的根节点debugShortDescription: [root],child: rootWidget,//根widget就是runAPP传入的MyApp()).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElementRenderBox?);if (isBootstrapFrame) {SchedulerBinding.instance.ensureVisualUpdate();}
}RenderView get renderView _pipelineOwner.rootNode! as RenderView;
/// 这儿创建了element树的根节点并返回了element
/// 也就是_renderViewElement其实就是element树的根
RenderObjectToWidgetElementT attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElementT? element ]) {if (element null) {owner.lockState(() {//创建element树的根节点 RenderObjectToWidgetElementelement createElement();assert(element ! null);//绑定BuildOwner通过 BuildOwner 构建需要构建的 elementelement!.assignOwner(owner);});//BuildOwner构建elementowner.buildScope(element!, () {element!.mount(null, null);});} else {element._newWidget this;element.markNeedsBuild();}return element!;
}现在为止出现了三棵树的根widget树RenderObjectToWidgetAdapter对象element树RenderObjectToWidgetElement对象renderObject树RenderView对象。接下来看mount方法作用就是将element添加到树种的parent节点上。//1RenderObjectToWidgetElement
override
void mount(Element? parent, Object? newSlot) {assert(parent null);//先看下mount方法都做了什么super.mount(parent, newSlot);//在这儿触发了_rebuild方法该方法调用了updateChild方法_rebuild();assert(_child ! null);
}//2, RenderObjectElement//创建了renderObjectoverridevoid mount(Element? parent, Object? newSlot) {super.mount(parent, newSlot);_renderObject (widget as RenderObjectWidget).createRenderObject(this);attachRenderObject(newSlot);_dirty false;}//因为widget是RenderObjectToWidgetAdapter类型其createRenderObject返回的了container//这个container就是我们之前传的renderViewRenderObjectWithChildMixinT createRenderObject(BuildContext context) container;//将renderObject挂载到RenderObject Tree上void attachRenderObject(Object? newSlot) {_slot newSlot;_ancestorRenderObjectElement _findAncestorRenderObjectElement();_ancestorRenderObjectElement?.insertRenderObjectChild(renderObject, newSlot);final ParentDataElementParentData? parentDataElement _findAncestorParentDataElement();if (parentDataElement ! null)_updateParentData(parentDataElement.widget as ParentDataWidgetParentData);}//3, Element//首先执行的mount主要是设置parentslot等的值void mount(Element? parent, Object? newSlot) {_parent parent;//element树上的父节点_slot newSlot;//子element在父节点上的位置_lifecycleState _ElementLifecycle.active;_depth _parent ! null ? _parent!.depth 1 : 1;//element树的深度if (parent ! null) {_owner parent.owner;}final Key? key widget.key;if (key is GlobalKey) {owner!._registerGlobalKey(key, this);}_updateInheritance();attachNotificationTree();}以上mount执行顺序为Element.mount-RenderObjectElement.mount-RenderObjectToWidgetElement.mount执行完毕后在Element.mount函数这里会触发_rebuild();在_rebuild()里面我们看到了Element.updateChild()。 void _rebuild() {try {//_child为null第二个入参就是MyApp()_child updateChild(_child, (widget as RenderObjectToWidgetAdapterT).child, _rootChildSlot);} catch (exception, stack) {...}}Element.updateChild()其实是element很重要的一个方法作为widget和renderobject的桥梁这个方法会根据不同的条件去创建、更新、删除element。这里可见就是build子widget这里就是build MyApp() //这里传的child是null
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {final Element newChild;if (child ! null) {//.......} else {newChild inflateWidget(newWidget, newSlot);}return newChild;}updateChild里有调用inflateWidget方法inflateWidget这个函数 Element inflateWidget(Widget newWidget, Object? newSlot) {...try {...//这儿就是为widget创建对应的element对象所以widget和element关联起来了final Element newChild newWidget.createElement();//又调用了mount方法将子element挂载到当前element结点上newChild.mount(this, newSlot);return newChild;} finally {...}}在这个函数里面就会触发 createElement去创建element ,element又会去调用对应类的mount函数。经过一系列的流程之后又会回到inflateWidget这个函数中再次触发新的mount函数形成一个层层调用不断创建parentElement到childElement的过程,这个过程完成了element tree的构建。2.2.2三棵树简介WIdget树存放渲染内容element树分离 WidgetTree 和真正的渲染对象的中间层 WidgetTree 用来描述对应的Element 属性,同时持有Widget和RenderObject存放上下文信息通过它来遍历视图树支撑UI结构。RenderObject树用于应用界面的布局和绘制负责真正的渲染保存了元素的大小布局等信息实例化一个 RenderObject 是非常耗能的。总结当应用启动时Flutter会遍历并创建所有的 Widget 形成 Widget Tree通过调用 Widget 上的 createElement() 方法创建每个 Element 对象形成 Element Tree。最后调用 Element 的 createRenderObject() 方法创建每个渲染对象形成一个 Render Tree。为什么要这样widget的重建开销非常小所以可以随意的重建因为它不一会导致页面重绘并且它也不一定会常常变化。 而renderObject如果频繁创建和销毁成本就很高了对性能的影响比较大因此它会缓存所有页面元素只是当这些元素有变化时才去重绘页面。而判断页面有无变化就依靠element了每次widget变化时element会比较前后两个widget只有当某一个位置的Widget和新Widget不一致才会重新创建Element和widget其他时候则只会修改renderObject的配置而不会进行耗费性能的RenderObject的实例化工作了。2.3绘制热身帧void scheduleWarmUpFrame() {if (_warmUpFrame || schedulerPhase ! SchedulerPhase.idle)return;_warmUpFrame true;final TimelineTask timelineTask TimelineTask()..start(Warm-up frame);final bool hadScheduledFrame _hasScheduledFrame;Timer.run(() {assert(_warmUpFrame);//1handleBeginFrame(null);});Timer.run(() {assert(_warmUpFrame);//2handleDrawFrame();resetEpoch();_warmUpFrame false;if (hadScheduledFrame)scheduleFrame();});lockEvents(() async {await endOfFrame;timelineTask.finish();});
}scheduleWarmUpFrame绘制的是根节点RenderObject对应的TransformLayer对象调用handleBeginFrame和handleDrawFrame方法通过pipelineOwner去执行layoutpaint等一些列操作。并且scheduleWarmUpFrame是立即去绘制的因为启动的显示要越快越好。后面的lockEvents也是为了等待预约帧绘制完成后再去执行其他的任务。