Flutter 表示层的内部结构
本文最后更新于 2021年4月4日 晚上
看了一篇讲 Flutter 的文章, 然后将这篇的内容浓缩了一下.
结构
参考这个链接, 也是 Flutter 社区中的一篇文章.
比如有如下代码:
1 |
|
下面就来对流程进行分析.
三棵树
在 runApp
首次执行时, 会发生如下动作:
- Flutter 创建一颗包含上面代码中三个
Widget
的树, 即 App–>Container–>Text. - Flutter 遍历
Widget
树, 针对每个Widget
调用其createElement
方法, 从而生成一颗对应的Element
树. - 同时, Flutter 调用每个
Element
的createRenderObject
方法, 从而生成第三棵RenderObject
树.
在这里面, 每个 Element
会持有其对应的 Widget
和 RenderObject
的引用.
RenderObject
它内部包含渲染 Widget 的所有逻辑, 包括布局, 绘制, 以及点击处理.
且它的初始化过程十分”昂贵”, 故策略就是尽量去重用已创建的 RenderObject.
而 Element 正是这样重用的媒介, 它作为不可变的 Widget 和可变的 RenderObject 间的桥梁, 在它内部包含了高效的比较算法, 通过比较 Widget 和 RenderObject 间的差异, 从而确定 RenderObject 的改变.
这样的话就可以尽量重用 RenderObject, 而且可以把改变只限制在某些节点或子树中, 从而达到很高的性能.
Widget 由于十分轻量, 故它们非常适合用于描述当前 APP 的状态(有时也称为App 的
configuration
).
而在日常开发中, 很少直接接触 Element
对象的原因是: Flutter 将 Element
对象包装在 BuildContext
接口对象内, 在 build(BuildContext context)
方法中获取封装了不同 Element
对象的 BuildContext
.
这也是为什么不同的 Widget
会对应不同的 BuildContext
的原因.
下一帧
由于 Widget
对象是不可变的, 当 configuration
发生改变(即 Widget 或其属性发生改变), Flutter 将会重建 Widget 树. 树重建时, 根据 Element
树从上往下依次对每个节点进行改变检测(对比 Widget
和对应的 RenderObject
), 流程如下:
从根节点开始,
若对应位置节点 Widget 类型发生改变, 则将三棵树中对应位置的对象均移除掉, 然后替换为新的(Widget, Element, RenderObject).
若 Widget 类型没有改变, 则只是更新
RenderObject
的配置(避免新建), 然后请求它进行重绘, 从而更新显示.没有改变的节点不会进行任何操作.
往后遍历继续执行上述两条规则,
具体的还需要看源码以完全确定.