生命周期
Flutter生命周期说白了就是回调方法(函数),主要是监听Widget事件,内存管理(销毁).
- 每一个
widget
都对应一个(或多个)Element
。Widget只是用于描述Element的一个配置文件,实际在Framework层管理页面的构建,渲染等,都是通过
Element完成,Element由Widget创建,并且持有
Widget对象,每一个Widget都会对应一个(或多个)Element。 - Element: 同时持有Widget和RenderObject,存放上下文信息,通过它来遍历视图树,支撑UI结构。
- 调用
setState()
相当于调用了markNeedsBuild
,即_element.markNeedsBuild(); - setState()过程其实只是将当前对应的Element标记为
脏dirty
,并且添加到_dirtyElements合中 - 重新渲染过程是一个增量改变,注意这里的
增量改变是指Element树和渲染render树
,而不是指widget树
,原有的不变的Element拿来复用
。widget肯定都是要重新创建,只是在渲染的时候在element树中再决定是重新渲染还是复用
。渲染时不是加载的widget树,而是Render树,决定是否重用是在element的canUpdate
。 - 为什么设计成三棵树呢?个人认为因为中间的Element树也对应contenxt,意思是
上下文
的意思,也就是说Element树持有Widget树和Render树的关系,这样处理效率更高。
widget与element与render
widget初始化时内部会隐式
调用createElement
;
StatelessWidget内部会调用
createElement
,同时将widget
实例当参数传递进去,并返回(stateful/less)Element
,而他们都继承自Element的子类ComponentElement
,接着调用ComponentElement
里的mount
方法的_firstBuild
,最终走到performReBuild
,这一步会拿出_widget
并调用build
方法,并把Element
当做参数传递,所以最终会调用到widget的build的方法,由此也可以证明BuildContext
就是element
,且Element有个属性_widget
用来指向外部widget变量。StateFulWidget会比上面流程多两部,在
Element创建后
立马调用widget.createState
,并把_state保存在Element。接着给state.widget赋值widget,这也是为什么能在state方法里只能调用widget的原因。Row、Cloumn
这类Widget里createElement返回的是Element的子类RenderObjectElement
,接着调用mount
方法里的createRenderObject
。
并不是所有的widget都会
独立
渲染,只有继承自RenderObjectWidget的才会创建renderObject对象。Flutter引擎是针对Render树进行渲染。
直接在页面节点调用setState()将会重新调用所有Widget(包括他们中的各种嵌套)的build()方法,如果我们的需求是一个较为复杂的页面,这样带来的开销消耗可想而知。当我们在一个高节点调用setState()的时候会构建再次build所有的Widget,虽然不一定挂载到Element树中,但是平时我们使用的Widget中往往嵌套多个其他类型的Widget,每个build()方法走下来最终也会带来不小的开销,因此通过各种状态管理方案,
Stream
等方式,只做局部刷新
,是我们日常开发中应该养成的良好习惯。
Key
Element的canUpdate
比较的是runtimeType
和Key
,运用了diff算法
,所以为了更加精确的区分oldwidget和newwidget,需要在widget的初始化方法里传入Key
:super(key:key);
GlobalKey:可以获取到对应的Widget的State对象,用来更新局部控件。_globalKey.currentState.setState();
。
优先级队列
then
优先级最高,微任务scheduleMicrotask
次之,Future
最次。
混合开发
Flutter和原生来回切换会消耗性能
和内存泄漏
。
Flutter和原生通信需要用到MethodChannel
.