Flutter的原生State刷新与GetX框架刷新的差异

Flutter开发中不同的布局刷新方式探讨

前言

我们团队使用 Flutter 开发也快两个月了,这次的事情是这样子的,我们项目是基于 GetX 实现的,同事写的一个长表单页面发生了刷新的卡顿。

在一顿逻辑判断与操作之后调用 GetX 框架的 update 刷新整个页面,而整个页面就被 GetBuilder 包裹的,要知道这可是整个页面可是有足足三个屏幕高度的表单啊。

这...你不卡谁卡。啊?那这... 到底怎么回事呢?

其实这么用 GetBuilder 与原生的 SetState 就没有区别了,都是全部rebuild,别被重新build吓到了,重新build不代表会重新渲染,但是性能消耗肯定是有的。

最简单的解决方式是分区使用 GetBuilder 或者使用局部刷新 Obx 来解决。

他们都是 GetX 的状态管理工具与原生的 setState 状态刷新还有点不一样,一起来看看吧。

一、GetBuilder刷新方案

GetX 的刷新方案分为手动刷新与自动刷新,GetBuilder 与 Obx ,分别对应范围刷新与局部刷新,基本的使用我就不介绍了,网上一搜大把的是。

先说 GetBuilder 的方案,直接上代码:

例如我们把一些布局封装到方法中,我们先加 8个 item 再说。

当然如果有条件最好是抽成类会更好,这里先偷懒...

此时如果我们调用 controller 的 update 会怎么样?它会刷新!

二、原生的刷新方案对比

我们改为原生刷新的方案:

每次刷新

可以看到是和 GetBuilder 是一样的效果,但是 GetBuilder 的效果是可以自定义作用域,可以选择一个或多个 GetBuilder 包括一个布局或容器,而不像 SetState 一样刷新全所有的布局。

引用一下大佬的原话【传送门】

当我们在一个高节点调用setState()的时候会构建再次build所有的Widget,虽然不一定挂载到Element树中,但是平时我们使用的Widget中往往嵌套多个其他类型的Widget,每个build()方法走下来最终也会带来不小的开销,因此通过各种状态管理方案,Stream等方式,只做局部刷新,是我们日常开发中应该养成的良好习惯。

引用岛上码农大佬的原话【传送门】

虽然setState的调用并没有像 Widget 层那样,在渲染控制层的 Element 那一层重新构建全部element。但是,这并不代表 setState 的使用没问题,首先,像之前篇章说的那样,它会重新构建整个 Widget 树,这会带来性能损耗;其次,由于整个 Widget 树改变了,意味着整棵树对应的渲染层Element对象都会执行 update方法,虽然不一定会重新渲染,但是这整棵树的遍历的性能开销也很高。因此,从性能上考虑,还是尽量不要使用 setState------除非,这个组件真的很简单,而且下级组件没有或者很少。

大家也可以看看这些文章如何追踪 setState 的源码实现。

三、Obx的局部刷新

其实网上也有很多局部刷新的方案,例如provider,StreamBuidler,ValueNotifier ,StatefulBuilder,Bedrock等等的框架或工具,我这里不做扩展了,只说一下 GetX 的响应式局部刷新。

ini 复制代码
RxString textContent = "刷新操作".obs;

我们把原本的数据改为Rx包装格式。

修改代码为Rx格式对象赋值:

修改使用RX对象的地方使用 Obx 包裹:

执行刷新我们可以看到,没有 rebuild 的 Log , 它已经刷新好了。

总结

原生State状态管理

setState 原生方式可以自行控制刷新,缺点是容器内其他布局都被重构了,如果需要避免重构重绘可能需要一些自定义逻辑(例如Key)去判断 canUpdate 操作。一般人都不会这么麻烦写这些东西的话不如使用 Obx 响应式精准指定刷新方便。

Obx 响应式状态管理

Obx 可以配合响应式字段局部的精准刷新避免父容器无效重构,缺点是字段变为响应式的Rx包装类,布局也需要被Obx包裹了,破坏了原生代码观赏性。

GetBuilder 状态管理器

GetBuilder 就是指定区域范围手动去刷新的,可以分区设置多个刷新区域,可选择单个控件或容器,在一些特定场景下有奇效,但是如果不理解滥用一样会导致性能问题。

那么到底要不要用 GetX ?

伪命题,用不用都行,看团队,看项目综合考虑,不过毕竟它是底层架构而不是功能模块,不能像功能模块(权限,多媒体,路径管理等)封装成引擎类可以随时替换。一旦你使用了 GetX 大概率以后都是换不下来,如果强行要换底层框架代价极大。

说这些并不是为了贬低 GetX 也不是为了安利 GetX,不吹不黑如果你已经用了 GetX 不如躺下来好好享受,无需再纠结原生的刷新,破坏了变量属性、破坏了 Widget 结构之类的纠结了。

关于 GetX 的刷新机制解析,网上有很多,我推荐大家可以看看呆呆大佬的分享【传送门】,当然如果大家对 setState 的原理感兴趣,我文中已经贴出了链接可供大家参的。

如果躺平接受了 GetX 的刷新方案,GetBuilder 与 Obx 两者结合,一个指定区域范围手动刷新,一个是局部控件点对点刷新,一个整体一个局部两者配合使用,基本上可以覆盖任何场景,并且相对性能也会比原生 setState 要好(理论上)。

那么本期内容就到这里,如讲的不到位或错漏的地方,希望同学们可以评论区指出。有更多更好的方案也欢迎大家评论区交流。

如果感觉本文对你有一点点点的启发,还望你能点赞支持一下,你的支持是我最大的动力啦。

Ok,这一期就此完结。

相关推荐
Python私教4 小时前
macOS 中搭建 Flutter 开发环境
flutter·macos
明似水8 小时前
掌握 Flutter 中的 `Overlay` 和 `OverlayEntry`:弹窗管理的艺术
javascript·flutter
Flutter社区19 小时前
使用 Flutter 3.19 更高效地开发
flutter·dart
Forever不止如此1 天前
【CustomPainter】绘制圆环
flutter·custompainter·圆环
wills7771 天前
Flutter Error: Type ‘UnmodifiableUint8ListView‘ not found
flutter
AiFlutter2 天前
Flutter之Package教程
flutter
Mingyueyixi2 天前
Flutter Spacer引发的The ParentDataWidget Expanded(flex: 1) 惨案
前端·flutter
crasowas2 天前
Flutter问题记录 - 适配Xcode 16和iOS 18
flutter·ios·xcode
老田低代码3 天前
Dart自从引入null check后写Flutter App总有一种难受的感觉
前端·flutter