当前位置: 首页 > news >正文

建立网站平台做网站虚拟主机好还是

建立网站平台,做网站虚拟主机好还是,泊头建网站,龙岗中心城有学网站建设目录 三棵树的关系树的构建过程1.updateChild函数#xff08;element的复用#xff09;2.inflateWidget函数3.mount函数3.1 componentElement的实现3.2 RenderObjectElement的实现3.2.1 attachRenderObject函数 4.performRebuild函数 总结三棵树创建流程 三棵树的关系 Flutt… 目录 三棵树的关系树的构建过程1.updateChild函数element的复用2.inflateWidget函数3.mount函数3.1 componentElement的实现3.2 RenderObjectElement的实现3.2.1 attachRenderObject函数 4.performRebuild函数 总结三棵树创建流程 三棵树的关系 Flutter 中存在 Widget 、 Element 、RenderObject 三棵树其中 Widget与 Element 是一对多的关系 Element 与 RenderObject 是一一对应的关系。 Element 中持有Widget 和 RenderObject 而 Element 与 RenderObject 是一一对应的关系除去 Element 不存在 RenderObject 的情况如 ComponentElement是不具备 RenderObject)当 RenderObject 的 isRepaintBoundary 为 true 时那么个区域形成一个 Layer所以不是每个 RenderObject 都具有 Layer 的因为这受 isRepaintBoundary 的影响。 Flutter 中 Widget 不可变每次保持在一帧如果发生改变是通过 State 实现跨帧状态保存而真实完成布局和绘制数组的是 RenderObject Element 充当两者的桥梁 State 就是保存在 Element 中。 一个可能的三棵树实例如下 先看下widget继承关系 对应的element继承关系: 通过上图可以看出每个widget对应一个element类型但是只有renderObjectElement类持有renderObject只有renderObjectWidget才能创建render对象。因此flutter视图的三棵树结构widget和element是一一对应的但是renderObjectElement才对应一个render节点。 树的构建过程 flutter视图的入口是 runApp(const MyApp());class MyApp extends StatelessWidget {const MyApp({super.key});overrideWidget build(BuildContext context) {return MaterialApp(/....省略);}}跟踪进入runApp函数 void runApp(Widget app) {//1 final WidgetsBinding binding WidgetsFlutterBinding.ensureInitialized();assert(binding.debugCheckZone(runApp));//2binding..scheduleAttachRootWidget(binding.wrapWithDefaultView(app))//3..scheduleWarmUpFrame(); }第一步首先确认engine绑定flutter framework是个阻塞过程scheduleAttachRootWidget 将app组件添加到根视图树上向native平台层请求绘制一帧的信号 先看第二步 void attachRootWidget(Widget rootWidget) {final bool isBootstrapFrame rootElement null;_readyToProduceFrames true;_rootElement RenderObjectToWidgetAdapterRenderBox(container: renderView,debugShortDescription: [root],child: rootWidget,).attachToRenderTree(buildOwner!, rootElement as RenderObjectToWidgetElementRenderBox?);if (isBootstrapFrame) {SchedulerBinding.instance.ensureVisualUpdate();}}RenderObjectToWidgetAdapter有两个成员child孩子widgetcontainer提供render功能容器将rootWidget作为的child元素renderView作为container。重点是attachToRenderTree函数 RenderObjectToWidgetElementT attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElementT? element ]) {if (element null) {//。。。省略owner.buildScope(element!, () {element!.mount(null, null);});} else {//。。。省略}return element!;}第一次element为空那么进入第一个判断首先调用buildScope内部会回调element!.mount方法 void buildScope(Element context, [ VoidCallback? callback ]) {if (callback null _dirtyElements.isEmpty) {return;}try {_scheduledFlushDirtyElements true;callback();_dirtyElements.sort(Element._sort);_dirtyElementsNeedsResorting false;int dirtyCount _dirtyElements.length;int index 0;while (index dirtyCount) {final Element element _dirtyElements[index];element.rebuild();index 1;//。。。省略}return true;}());}}首先回调callback接着对脏元素集合调用rebuild方法。第一次肯定列表是空的那么应该执行callback方法也就进入了element.mount方法中 overridevoid mount(Element? parent, Object? newSlot) {assert(parent null);super.mount(parent, newSlot);_rebuild();assert(_child ! null);}mount方法也是个关键函数函数的注释 将此元素添加到给定父级的给定插槽中的树中。 当新创建的元素添加到 树是第一次。使用此方法初始化状态 取决于有父母。独立于父级的状态可以 更容易在构造函数中初始化。 此方法将元素从“初始”生命周期状态转换为 “活动”生命周期状态。 重写此方法的子类可能也希望重写 [update] [visitChildren] [RenderObjectElement.insertRenderObjectChild] [RenderObjectElement.moveRenderObjectChild]以及 [RenderObjectElement.removeRenderObjectChild]。 此方法的实现应从调用继承的 方法如 ‘super.mountparent newSlot’。 注其中newSlot参数是parent renderObject的插槽位置对象parent的子renderObject组成一个顺序列表或者是单个节点插槽的结构是列表中的索引位置和前一个插槽元素的对象parent将插槽传递给child保存起来child可以确认自己在parent的布局位置。 首先调用_rebuild()方法 RenderObjectToWidgetElement类 void _rebuild() {_child updateChild(_child, (widget as RenderObjectToWidgetAdapterT).child, _rootChildSlot); } Element类 Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {//。。。省略final Element newChild;if (child ! null) {bool hasSameSuperclass true;// When the type of a widget is changed between Stateful and Stateless via// hot reload, the element tree will end up in a partially invalid state.// That is, if the widget was a StatefulWidget and is now a StatelessWidget,// then the element tree currently contains a StatefulElement that is incorrectly// referencing a StatelessWidget (and likewise with StatelessElement).//// To avoid crashing due to type errors, we need to gently guide the invalid// element out of the tree. To do so, we ensure that the hasSameSuperclass condition// returns false which prevents us from trying to update the existing element// incorrectly.//// For the case where the widget becomes Stateful, we also need to avoid// accessing StatelessElement.widget as the cast on the getter will// cause a type error to be thrown. Here we avoid that by short-circuiting// the Widget.canUpdate check once hasSameSuperclass is false.//1bool hasSameSuperclass true;final int oldElementClass Element._debugConcreteSubtype(child);final int newWidgetClass Widget._debugConcreteSubtype(newWidget);hasSameSuperclass oldElementClass newWidgetClass;if (hasSameSuperclass child.widget newWidget) {// We dont insert a timeline event here, because otherwise its// confusing that widgets that dont update (because they didnt// change) get charged on the timeline.if (child.slot ! newSlot) {updateSlotForChild(child, newSlot);}newChild child;} else if (hasSameSuperclass Widget.canUpdate(child.widget, newWidget)) {if (child.slot ! newSlot) {updateSlotForChild(child, newSlot);}child.update(newWidget);newChild child;} else {deactivateChild(child);// The [debugProfileBuildsEnabled] code for this branch is inside// [inflateWidget], since some [Element]s call [inflateWidget] directly// instead of going through [updateChild].newChild inflateWidget(newWidget, newSlot);}} else {// The [debugProfileBuildsEnabled] code for this branch is inside// [inflateWidget], since some [Element]s call [inflateWidget] directly// instead of going through [updateChild].newChild inflateWidget(newWidget, newSlot);}return newChild;}1.updateChild函数element的复用 更新element对象分为下面几种情况 child不为空 element的创建首先判断旧的child element元素是否和新的widget元素class类型匹配对应匹配关系如下 elementwidgethasSameSuperclassStatefulElementStatefulWidgetYStatelessElementStatelessWidgetY 如果匹配hasSameSuperclass并且element.widget和新传递进来的newWidget对象相同那么说明widget是复用的我们知道widget是不可变的每次都要新建widget所以在使用const定义的widget的情况下widget使用的常量对象符合这个判断对child做slot更新newChild更新为child。如果匹配hasSameSuperclass并且widget.canUpdate判断成立这个判断判断element对应的widget和newWidget对应的class类型和key是否相同这种情况下如果给widget定义了globalKey并且参数使用const定义的话那么判断是可以成立的对child做slot更新调用child.update(newWidget)newChild更新为child。 2.1 child.update方法首先更新element的widget然后根据子类的覆写实现statelessElement的实现是直接调用element的rebuild方法statefullElement实现是更新state的widget并且回调didUpdateWidget钩子函数然后调用rebuild方法 static bool canUpdate(Widget oldWidget, Widget newWidget) {return oldWidget.runtimeType newWidget.runtimeType oldWidget.key newWidget.key;}如果旧的element无法更新的话需要解除绑定关系将旧的element回收用于后面的视图build复用然后inflateWidget根据newWidget新建一个element。 protectedvoid deactivateChild(Element child) {assert(child._parent this);child._parent null;child.detachRenderObject();owner!._inactiveElements.add(child); // this eventually calls child.deactivate()}child为空 inflateWidget根据newWidget新建一个element 2.inflateWidget函数 Element inflateWidget(Widget newWidget, Object? newSlot) {//。。。s省略try {final Key? key newWidget.key;if (key is GlobalKey) {final Element? newChild _retakeInactiveElement(key, newWidget);if (newChild ! null) {newChild._parent nullnewChild._activateWithParent(this, newSlot);final Element? updatedChild updateChild(newChild, newWidget, newSlot);return updatedChild!;}}final Element newChild newWidget.createElement();newChild.mount(this, newSlot);return newChild;}}首先判断newWidget是否拥有globalKey如果有的话尝试从复用池中获取拥有相同key的element元素然后对该元素进行updateChild操作这样又回到上面的起点了这样看起来element更新是深度递归的。如果没有key那么直接创建一个新的element然后element进行mount挂载操作也就是将element加入到这个element树中。 3.mount函数 重点看看mount函数 void mount(Element? parent, Object? newSlot) {assert(_lifecycleState _ElementLifecycle.initial);assert(_parent null);assert(parent null || parent._lifecycleState _ElementLifecycle.active);assert(slot null);_parent parent;_slot newSlot;_lifecycleState _ElementLifecycle.active;_depth _parent ! null ? _parent!.depth 1 : 1;if (parent ! null) {// Only assign ownership if the parent is non-null. If parent is null// (the root node), the owner should have already been assigned.// See RootRenderObjectElement.assignOwner()._owner parent.owner;}assert(owner ! null);final Key? key widget.key;if (key is GlobalKey) {owner!._registerGlobalKey(key, this);}_updateInheritance();attachNotificationTree();}首先对该widget进行参数判断因为是新的widget所以依赖关系都是空的这里需要进行parent关联操作生命周期设置树的深度设置owner是和parent使用的同一个注册全局key。_updateInheritance保存来自parent的_inheritedElements对象这个对象集合里面包含着这棵树所有的inheritedElement如果自己也是inheritedElement也要将自己加入集合这个类型的element具有从上下文继承数据的功能可以根据类型读取数据对应类型数据改变可以通知所有依赖这个数据的inheritedElement去更新视图。attachNotificationTree保存parent的_notificationTree集合如果自己是NotifiableElementMixin类型会将自己加入到parent._notificationTree集合中这个集合是接受通知集合一般的widget也不需要这个功能不去深究。 注 从上面代码分析可知mount是element从initial - active的时间点。 mount是element基本接口子类会对其进行复写并且super调用 3.1 componentElement的实现 componentElement类是负责组合子element的作用的相当于Android View视图中的viewGroup但是它也没有绘制功能仅仅是负责排列组合子element。 component Element的复写 void mount(Element? parent, Object? newSlot) {super.mount(parent, newSlot);firstBuild();}void _firstBuild() {rebuild(); // This eventually calls performRebuild.}void rebuild({bool force false}) {、//。。。省略if (_lifecycleState ! _ElementLifecycle.active || (!_dirty !force)) {return;}//。。。省略try {performRebuild();}}会进行一次rebuild操作内部直接调用的performRebuild()。 3.2 RenderObjectElement的实现 RenderObjectElement类是起绘制作用的element相当于Android View视图中的view视图的正真的绘制操作都在里面实现。 RenderObjectElement复写 void mount(Element? parent, Object? newSlot) {super.mount(parent, newSlot);_renderObject (widget as RenderObjectWidget).createRenderObject(this);attachRenderObject(newSlot);super.performRebuild(); // clears the dirty flag}由RenderObjectWidget创建RenderObject这个RenderObject是正真实现绘制功能的类。attachRenderObject函数主要是将parent.newSlot传递给自己然后和parent建立关联这个关联主要是renderTree的关联。 3.2.1 attachRenderObject函数 void attachRenderObject(Object? newSlot) {assert(_ancestorRenderObjectElement null);_slot newSlot;_ancestorRenderObjectElement _findAncestorRenderObjectElement();_ancestorRenderObjectElement?.insertRenderObjectChild(renderObject, newSlot);final ParentDataElementParentData? parentDataElement _findAncestorParentDataElement();if (parentDataElement ! null) {_updateParentData(parentDataElement.widget as ParentDataWidgetParentData);}}_ancestorRenderObjectElement RenderObjectElement? _findAncestorRenderObjectElement() {Element? ancestor _parent;while (ancestor ! null ancestor is! RenderObjectElement) {ancestor ancestor._parent;}return ancestor as RenderObjectElement?;}向上递归获取第一个RenderObjectElement类型的祖先然后将当前子renderObject插入到这个祖先RenderObjectElement的孩子中或者孩子队列中。 可以看出也不是所有的element都是RenderObjectElement类型的componentElement以及它的子类就不是那么就会被跳过继续向上递归。 进而也就有了文章开头的那三棵树的关系widget和element是一对一关系的build过程中element创建一定需要widget去配置或者更新renderObject的创建只有RenderObjectWidget才有这个接口功能因此像componentElement类型的就没有renderObject。 SingleChildRenderObjectElement类的实现这个类只包含一个单独的renderObject直接赋值子child void insertRenderObjectChild(RenderObject child, Object? slot) {final RenderObjectWithChildMixinRenderObject renderObject this.renderObject as RenderObjectWithChildMixinRenderObject;assert(slot null);assert(renderObject.debugValidateChild(child));renderObject.child child;assert(renderObject this.renderObject);}MultiChildRenderObjectElement类的实现这个类包含多个renderObject按照自己定义的排列规则排列子renderObject将child插入到子child队列中对应的位置上面说了slot已经将child的位置定下来了可以根据slot的位置将child插入到指定位置。 void insertRenderObjectChild(RenderObject child, IndexedSlotElement? slot) {final ContainerRenderObjectMixinRenderObject, ContainerParentDataMixinRenderObject renderObject this.renderObject;assert(renderObject.debugValidateChild(child));renderObject.insert(child, after: slot.value?.renderObject);assert(renderObject this.renderObject);}void insert(ChildType child, { ChildType? after }) {adoptChild(child);_insertIntoChildList(child, after: after);}void adoptChild(RenderObject child) {setupParentData(child);markNeedsLayout();markNeedsCompositingBitsUpdate();markNeedsSemanticsUpdate();child._parent this;if (attached) {child.attach(_owner!);}redepthChild(child);}adoptChild函数所作的事情是绑定parentData数据child根据parent的布局数据layout的时候有用接下来就是标记parent需要重新layoutchild和parent进行关联。 void _insertIntoChildList(ChildType child, { ChildType? after }) {final ParentDataType childParentData child.parentData! as ParentDataType;_childCount 1;assert(_childCount 0);if (after null) {// insert at the start (_firstChild)childParentData.nextSibling _firstChild;if (_firstChild ! null) {final ParentDataType firstChildParentData _firstChild!.parentData! as ParentDataType;firstChildParentData.previousSibling child;}_firstChild child;_lastChild ?? child;} else {final ParentDataType afterParentData after.parentData! as ParentDataType;if (afterParentData.nextSibling null) {// insert at the end (_lastChild); well end up with two or more childrenassert(after _lastChild);childParentData.previousSibling after;afterParentData.nextSibling child;_lastChild child;} else {// insert in the middle; well end up with three or more children// set up links from child to siblingschildParentData.nextSibling afterParentData.nextSibling;childParentData.previousSibling after;// set up links from siblings to childfinal ParentDataType childPreviousSiblingParentData childParentData.previousSibling!.parentData! as ParentDataType;final ParentDataType childNextSiblingParentData childParentData.nextSibling!.parentData! as ParentDataType;childPreviousSiblingParentData.nextSibling child;childNextSiblingParentData.previousSibling child;assert(afterParentData.nextSibling child);}}}插入操作以下几种情况 前驱为空那么当前插入的child是队列的第一个元素直接插入前驱不为空如果前驱的next指针为空那么前驱是尾部元素child插入到尾部前驱不为空并且前驱在队列中间那么将child插入到前驱的后面。 parentDataElement ParentDataElementParentData? _findAncestorParentDataElement() {Element? ancestor _parent;ParentDataElementParentData? result;while (ancestor ! null ancestor is! RenderObjectElement) {if (ancestor is ParentDataElementParentData) {result ancestor;break;}ancestor ancestor._parent;}}向上递归获取第一个parentDataElement类型的祖先然后将当前子renderObject传递给祖先祖先会验证自己的data和子child的data的数据是否一致不一致会标记脏下一帧会重新layout否则不管。 void _updateParentData(ParentDataWidgetParentData parentDataWidget) {if (applyParentData) {parentDataWidget.applyParentData(renderObject); }}void applyParentData(RenderObject renderObject) {//。。。s省略if (needsLayout) {markNeedsLayout();}}其中实现了ParentDataWidget的子类有 这些布局也说明了一个问题子child的布局属性变化会导致parent布局重新layout这样好像会影响性能。 4.performRebuild函数 performRebuild也是element的基本接口 void performRebuild() {_dirty false;}不同的子类也会有不同的实现component Element的复写 void performRebuild() {Widget? built;try {built build();}try {_child updateChild(_child, built, slot);}}Widget build();调用build方法构建出本element所需要的widget组件widget的build函数由子类实现提供componentElement的子类主要有StatelessElementStatefulElementProxyElement三个 1.1 StatelessElement使用child的widget来构建Widget build() (widget as StatelessWidget).build(this); 1.2 ProxyElement直接使用child Widget build() (widget as ProxyWidget).child; 1.3 StatefulElement使用state来创建 Widget build() state.build(this); 调用updateChild用新构建出的widget去更新旧的child element元素这个updateChild方法上面已经讲过可以知道如果element的子element还有child的话一直递归调用updateChild函数可以推测出element树的构建也是深度递归进行的。 总结三棵树创建流程 上面梳理了整个树创建的过程调用链updateChild - inflateWidget - mount - performRebuild - child - updateChild递归调用 假如有以下widget树 return Container(decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(8.0.r)),border: Border.all(color: CtrColor.lineRegular, width: 1),),child: const Row(children: [Image(image: AssetImage(static/images/ic_net_error.png)),Text(data)],));可以画出整个树创建的流程图
http://www.lebaoying.cn/news/28999.html

相关文章:

  • 工程房地产行业一条龙网站提供深圳网站制作公司
  • 做磁力链网站企业营销策略有哪几种
  • 接任务做兼职的的网站百度贴吧网页版登录入口
  • 四川建设厅网站郑州网站建设代运营
  • 潍坊网站建设培训班湖南企业竞价优化公司
  • 百度快照抓取的是网站哪里的内容在线做带字头像的网站
  • 网站显示域名专线可以做网站
  • 宁波市节约型机关建设考试网站网站建设实录
  • 郑州网站建设老牌公司辽宁工程建设信息网诚信库怎么填
  • 信息发布网站开发模板现在有没有免费的网站
  • 网站开发公司 商业计划书如何制作app软件编程
  • 交易类网站seo怎么做如何自己弄一个网站
  • 网站维护排名房地产微网站建设栏目设计
  • wap网站前台设计企业网店推广策略
  • 猎头网招聘哈尔滨网站优化流程
  • 网站长春网站建设wordpress 视频主题
  • 做网站推广 需要ftp海南电子商务网站
  • 自己做盈利视频网站怎么更改wordpress文件上传大小
  • 查询个人房产信息网站代理平台什么意思
  • 一些做系统的网站公司网站如何在百度上能搜索到
  • 一个人做网站 优帮云外包网站开发
  • 建交互网站需要多少钱宁波租房网
  • 深圳建企业网站推广软件赚钱的平台
  • 怎么套网站300平私人会所装修设计
  • 蓝色中网站成都网站建设推广港哥
  • 网站建设实力宣传海报lnmp wordpress 主题
  • 设计网站大全铲鼠湖南岚鸿相信seo引擎优化怎么做
  • 网站怎么做权重wordpress 删除 加载中
  • 昆明做网站需要多少钱江西人才网官方网站
  • 自己服务器建网站网页翻译软件