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,这一期就此完结。

相关推荐
火柴就是我6 小时前
flutter 之真手势冲突处理
android·flutter
Speed1237 小时前
`mockito` 的核心“打桩”规则
flutter·dart
法的空间7 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
恋猫de小郭7 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
玲珑Felone8 小时前
从flutter源码看其渲染机制
android·flutter
ALLIN1 天前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei1 天前
Flutter 国际化
flutter
Dabei1 天前
Flutter MQTT 通信文档
flutter
Dabei1 天前
Flutter 中实现 TCP 通信
flutter
孤鸿玉1 天前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter