上篇文章中,我们知道了 Flutter 的视图树中有三种树
Widget
Element
RenderObject
而且,Flutter 建议,Widget 最好是 不可变的(immutable)。
问题一
但是为什么呢?如果我们的页面数据发生变化,那么视图也需要发生变化,怎么办呢?
flutter 界面开发是一种响应式编程,主张 simle is fast
flutter 设计的初衷是希望数据变化时,发送通知到对应的可变更节点,这个节点可能是一个 StatefullWidget 子节点,也可能是 rootWidget
,由上到下重新 create widget 树进行刷新。
重点是:重新 create widget树
这样的话,思路就比较简单了,就不用关心数据变更会影响到哪些节点了;
而且,将 widget 设置成不可变的,也节省了很多资源。
这个时候,问题二来了
问题二
更新数据,需要更新视图,就得重新创建 Widget ,那么 另外两颗树🌲也会重新创建吗?
当然不会啦~
如果需要再重新创建一遍,那么这种复杂度和使用 可变的 Widget 就基本没什么区别了。
widget 只是一个 数据结构的配置,是非常轻量的,耗费的资源也是很少的,再加上 flutter 团队对 widget 的创建、销毁都做了优化,所以不用担心整个 widget 树重新创建所带来的性能问题。
但是 RenderObject 就不一样了,RenderObject 涉及到 layout、paint 等复杂操作,是一个真正渲染的 view,整个 view 树重新创建开销就很大了。
既然这样,那么第三个问题也来了:
问题三
只重新创建 Widget ,不重新创建 Element 和 RenderObject,那么怎么实现「视图的更新」呢?
方便起见,大家看图吧~
视图树更新原则
需要注意:
element.child.widget == widget.build() 时,不会触发子树的 update,当触发 update 的时候,如果没有生效,要注意 widget 是否使用就 widget,没有 new widget,导致 update 流程走到改 widget 就停止了
子树的深度变化,会引起子树重建,如果子树是一个复杂度很高的树,可以使用 GlobalKey 作为子树 widget 的key。因为,GlobalKey 具有缓存功能。
问题四
怎样才能出发「视图树更新」即界面更新
-
全局更新:调用 runApp(rootWidget), 这个一般是 flutter 启动时调用,之后不会再调用了
-
局部子树更新,将该子树做 StatefullWidget 的一个子 widget,并创建对应的 State 类实例,通过调用 state.setState() 触发该子树的刷新
总结
这几个问题,对于理解 Flutter 界面更新,应该有一定的帮助吧~~,图是自己对照着「语雀」上面的文章画的,大家有兴趣可以去看看
真心推荐
网友评论