本文为稀土技术社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!

这是 《Flutter 工程化结构挑选》 系列的第六篇 ,就像之前说的,这个系列仅仅单纯告知你,创立一个 Flutter 工程,或许说搭建一个 Flutter 工程脚手架,应该怎么快速挑选合适自己的功能模块,或许说这是一个指引系列,所以比较合适新手同学。

其实这是我最不想写的一个篇

状况办理是 Flutter 里 ♾️ 的话题,本质上 Flutter 里的状况办理便是传递状况和依据 setState 的封装,状况办理结构解决的是怎么更优雅地同享状况和调用 setState

那为什么我不是很想写状况办理的比照内容

首要由于它很繁,繁体的煩,从 Flutter 发布到现在,scoped_modelBLoCProviderflutter_reduxMobXfish_reduxRiverpodGetX 等各类结构“百家争鸣”,尽管这关于社区来说是这是功德,可是关于普通开发者来说很简略形成过度挑选困难症,特别早期不少人被各种结构“伤害过”。

Flutter 工程化框架选择 — 状态管理何去何从

其次,状体办理在 Flutter 里一向是一个“敏感”话题,每次聊到状况办理就绕不开 GetX ,可是一旦聊 GetX 又会变成“立场”问题,所以一向以来我都不是很喜欢写状况办理的内容。

Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从

所以本来应该在第一篇就出现的内容,一向被拖到现在才放出来,这儿提早声明一些,本篇不会像之前相同从巨细和功能等方面去做比照,由于关于状况办理结构来说这没什么含义:

  • 集成后对巨细的影响可能还不如一张图片
  • 功能首要取决于开发者的习气,在状况办理结构上比照功能其实很主观

当然,假如你对集成后对巨细的影响真的很在意,那能够在打包时经过 --analyze-size 来生成 analysis.json 文件用于比照剖析:

flutter build apk --target-platform android-arm64 --analyze-size

上诉命令在执行之后,会在 /Users/你的用户名/.flutter-devtools/ 目录下生成一个 apk-code-size-analysis_01.json 文件,之后咱们只需求翻开 Flutter 的 DevTools 下的 App Size Tooling 就能够进行剖析。

Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从

例如这儿是将 RiverpodGetX 在同一项项目集成后导出不同 json 在 Diff 进行比照,能够看到此时差异也就在 78.5kb ,这个差异巨细还不如一张 png 资源图片的影响大。

Flutter 工程化框架选择 — 状态管理何去何从

所以本次首要是从这些状体办理结构自身的特色动身,简略罗列它们的优劣,至于最后你觉得哪个合适你,那就见仁见智了

本篇仅仅告知你它们的特色和怎么去挑选,并不会深入详细解说,假如对完成感兴趣的能够看曾经共享过的文章:

  • Flutter Riverpod 全面深入解析

  • 全面了解 State 与 Provider

  • 全面深入了解状况办理规划

Provider

2019 年的 Google I/O 大会 Provider 成了 Flutter 官方新引荐的状况办理方式之一,它的特色便是: 不杂乱,好了解,代码量不大的情况下,能够便利组合和操控改写颗粒度 , 其实一开端官方也有一个 flutter-provide ,不过后来宣告GG , Provider 成了它的代替品。

⚠️留意,providerflutter-provide 多了个 r,所以不要再看着 provide 说 Provider 被弃坑了。

简略来说,Provider 便是针对 InheritedWidget 的一个包装工具,他让 InheritedWidget 的运用变得更简略,在往下同享状况的一起,能够经过 ChangeNotifierStreamFuture 合作 Consumer* 组合出多样的更新形式。

所以运用 Provider 的好处之一便是简略,一起你能够经过 Consumer* 等来决议改写的颗粒度,其实也便是 BuildContextof(context) 时的颗粒度操控。

挂号到 InheritedWidget 里的 context 决议了更新是 rebuild 哪个 ComponentElement ,感兴趣的能够看 全面了解 State 与 Provider

当然,尽管一向说 Provider 简略,可是其实仍是有一些略微“杂乱”的地方,例如 select

Provider 里 select 是对 BuildContext 做了 “二次挂号” 的行为,便是曾经你用 context 是 watch 的时分 ,是直接把这个 Widget 挂号到 Element 里,有更新就通知。

Flutter 工程化框架选择 — 状态管理何去何从

可是 select 做了二次处理,便是用 dependOnInheritedElement 做了颗粒化的判别,假如是不等于了才更新,所以它对 context 有要求,如下图对便是对 context 类型进行了判别。

Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从

所以 select 算是 Provider 里的“小魔法“之一,总的来说 Provider 是一个契合 Flutter 的行为习气,可是不大契合前端和原生的开发习气的优异状况办理结构

长处:

  • 简略好保护
  • read、watch、select 供给更简练的颗粒度办理
  • 官方引荐

缺陷:

  • 相对依靠 Flutter 和 Widget
  • 需求依靠 Context

最后顺带辟个谣,之前有 “风闻” Provider 要被弃坑的说法,作者针对这个也有相应对澄清,所以你仍是能够持续安心运用 Provider。

Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从

Riverpod

Riverpod 和 Provider 是同个作者,由于 Provider 存在某些限制性,所以作者依据 Provider 这个单词重新排列组合成 Riverpod

Flutter 工程化框架选择 — 状态管理何去何从

假如说 Provider 是 InheritedWidget 的封装,那 Riverpod 便是在 Provider 的根底上重构出更灵敏的操作能力,最直观的便是 Riverpod 中的 Provider 能够随意写成大局,而且不依靠 BuildContext 来编写咱们需求的事务逻

留意: Riverpod 中的 Provider 和前面的 Provider 没有联系。

Flutter 工程化框架选择 — 状态管理何去何从

在 Riverpod 里基本是每一个 “Provider” 都会有一个自己的 “Element” ,然后经过 WidgetRef 去 Hook 后成为 BuildContext 的代替,所以这便是 Riverpod 不依靠 Context 的 “魔法” 之一

⚠️这儿的 “Element” 不是 Flutter 概念里三棵树的 Element,它是 Riverpod 里 Ref 目标的子类Ref 首要供给 Riverpod 内的 “Provider” 之间交互的接口,而且供给一些抽象的生命周期办法,所以它是 Riverpod 里的独有的 “Element” 单位。

别的比照 Provider ,Riverpod 不需求依靠 Flutter ,所以也不需求依靠 Widget,也便是不依靠 BuildContext ,所以能够支撑大局变量界说 “Provider” 目标。

长处:

  • 在 Provider 的根底上愈加灵敏的完成,
  • 不依靠 BuildContext ,所以事务逻辑也无需注入 BuildContext
  • Riverpod 会尽可能经过编译时安全来解决存在运行时反常问题
  • 支撑大局界说
  • ProviderReference 能更好解决嵌套代码

缺陷:

  • 完成愈加杂乱
  • 学习成本进步

目前从我个人视点看,我觉得 Riverpod 时当前之下状况办理的最佳挑选,它灵敏且专注,体验上也更契合 Flutter 的开发习气

留意,许多人一开端只依靠 riverpod 然后发现一些封装目标不存在,由于 riverpod 是不依靠 flutter 的完成,所以在 flutter 里运用时不要忘记要依靠 flutter_riverpod

BLoC

BLoC 算是 Flutter 早期比较知名的状况办理结构,它相同是存在 blocflutter_bloc 这样的依靠联系,它是依据事情驱动来完成的状况办理

Flutter 工程化框架选择 — 状态管理何去何从

flutter_bloc 依据事情驱动的核心便是 Stream 和 Provider , 是的, flutter_bloc 依靠于 Provider,然后在其根底上规划了依据 Stream 的事情响应机制。

所以严厉含义上 BLoC 其实是 Provider + Stream ,假如你一向很习气依据事情流开发形式,那么 BLoC 就很合适你,可是其实从我个人体验上看,BLoC 在开发节奏上并不是快,相反还有点费事,不过优势也很明显,依据 Stream 的封装能够更便利做一些事情状况的监听和转化。

BlocSelector<BlocA, BlocAState, SelectedState>(
  selector: (state) {
    // return selected state based on the provided state.
  },
  builder: (context, state) {
    // return widget here based on the selected state.
  },
)
MultiBlocListener(
  listeners: [
    BlocListener<BlocA, BlocAState>(
      listener: (context, state) {},
    ),
    BlocListener<BlocB, BlocBState>(
      listener: (context, state) {},
    ),
    BlocListener<BlocC, BlocCState>(
      listener: (context, state) {},
    ),
  ],
  child: ChildA(),
)

长处:

  • 代码愈加解耦,这是事情驱动的特性
  • 把状况更新和事情绑定,能够灵敏得完成状况阻拦,重试乃至撤回

缺陷:

  • 需求写更多的代码,开发节奏会有点影响
  • 接纳代码的新保护人员,缺乏有效文档时简略陷入对着事情和事务蒙圈
  • 项目后期事情简略混乱交织

相似的库还有 rx_bloc ,相同是依据 Stream 和 Provider , 不过它选用了 rxdart 的 Stream 封装。

flutter_redux

flutter_redux 尽管也是 pub 上的 Flutter Favorite 的项目,可是现在的 Flutter 开发者应该都不怎么运用它,而刚好我在刚运用 Flutter 时运用的状况办理结构便是它。

Flutter 工程化框架选择 — 状态管理何去何从

其实前端开端者对 redux 可能会更了解一些,当时我刚好用 RN 项目切换到 Flutter 项目,在 RN 时代我就一向在运用 redux,flutter_redux 自然就成了我首选的状况办理结构。

其实这也是 Flutter 最有意思的,许多前端的状况办理结构都能够迁移到 Flutter ,例如 flutter_redux 里便是利用了 Stream特性,经过 redux 单向事情流的规划形式来完成解耦和拓宽。

Flutter 工程化框架选择 — 状态管理何去何从

在 flutter_redux 中,开发者的每个操作都仅仅一个 Action ,而这个行为所触发的逻辑完全由 middlewarereducer 决议,这样的规划在必定程度大将事务与UI阻隔,一起也一致了状况的办理。

当然缺陷也很明显,你要写一堆代码,开发逻辑必定程度上也不大契合 Flutter 的开发习气。

长处:

  • 解耦
  • 对 redux 开发友爱
  • 合适中大型项目里协作开发

缺陷:

  • 影响开发速度,要写一堆模版
  • 不是很贴合 Flutter 开发思路

说到 redux 就不得不说 fish_redux ,假如说 redux 是搭积木,那闲鱼最早开源的 fish_redux 能够说是积木界的乐高,闲鱼在 redux 的根底上提出了 Comoponent 的概念,这个概念下 fish_redux 是从 ContextWidget 等地方就开端全面“侵略”你的代码,从而带来“超级赛亚人”版的 redux

Flutter 工程化框架选择 — 状态管理何去何从

所以不管是 flutter_redux 仍是 fish_redux 都是很合适团队协作的开发结构,可是它的开发体验和开发进程,注定不是很友爱

GetX

GetX 能够说是 Flutter 界内大名鼎鼎,Flutter 不能没有 GetX 就像程序员不能没有 PHP ,GetX 很好用,很具备话题,很全面一起也很 GetX

Flutter 工程化框架选择 — 状态管理何去何从

严厉含义上说现在 GetX 现已不是一个简略的状况办理结构,它是一个一致的 Flutter 开发脚手架,在 GetX 内你能够找到:

  • 状况办理
  • 路由办理
  • 多语言支撑
  • 页面托管
  • Http GetConnect
  • Rx GetStream
  • 各式各样的 extension

能够说大部分你想到的 GetX 里都有,乃至还有依据 GetX 的 get_storage 完成纯 Dart 文件级 key-value 存储支撑。

所以许多时分运用 GetX 开发乃至不需求关怀 Flutter ,当然这也导致经常遇到的古怪情况:我们的问题集中在 GetX 里怎么 xxxx,而不是 Flutter 怎么 xxxx所以 GetX 更像是依附在 Flutter 上的解决计划

Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从

当然,运用 GetX 最直观的便是不需求 BuildContext ,乃至是你在路由跳转时都不需求关怀 Context ,这就让你的代码看起来很“干净”,把整个开发进程做到“面向 GetX 开发”的效果

别的 GetX 和 Provider 等相比还具备的特色是:

  • Get.putGet.findGet.to 等操作完全无需 Widget 介入
  • 内置的 extension 如各类根底相似的 *.obs 经过 GetStream 完成了如 var count = 0.obs;Obx(() => Text("${controller.name}")); 这样的简化绑定操作

那 GetX 是怎么脱离 Context 的依靠?说起来也不杂乱,例如 :

  • GetMaterialApp 内经过一个会有一个 GlobalKey 用于装备 MaterialAppnavigatorKey ,这样就能够经过大局的 navigatorKey 获取到 NavigatorState ,从而调用 push API 翻开路由

  • Get.putGet.find 是经过一个内部大局的静态 Map 来办理,所以在传递和存放时就脱离了 InheritedWidget ,结合 Obx ,在对获取到的 GetxController 的 value 时会有个 addListener 的操作,从而完成 Stream 的绑定和更新

Flutter 工程化框架选择 — 状态管理何去何从
Flutter 工程化框架选择 — 状态管理何去何从

能够说 GetX 内部有许多“魔法”,这些魔法或许是对 Flutter API 的 Hook、或许是直接脱离 Flutter 规划的自界说完成,总的来说 GetX “有自己的想法”

这也就带来一个了个问题,许多人新手一上手便是 GetX ,然后对 Flutter 一知半解,特别是深度解绑了 Context 之后,许多 Flutter 问题就变成了 GetX 上怎么 xxxx,例如前面的: Flutter GetX 怎么调用谷歌地图这种问题

Flutter 工程化框架选择 — 状态管理何去何从

假如运用 GetX 而不去考虑和了解 GetX 的完成,就很简略在 Flutter 的路上走歪,比方上面各种很根底的问题。

这其实也是 GetX 的最大问题:GetX 做的许多,它侵略到许多范畴,而且它具有许多“魔法”,这些“魔法”让 Flutter 开发者不知布局的脱离了本来应有的轨道。

Flutter 工程化框架选择 — 状态管理何去何从

当然,你说我便是想完成需求,好用就行,何必关怀它们的完成呢?从这个视点看 GetX 无疑是非常不错的挑选,只要 GetX 能持续保护下去并把“魔法”持续兼容。

大概便是:GetX “王国” 对初级开发者友爱,可是“魔法全家桶”其实对社区的健康发展很丧命

长处:

  • 瑞士军刀式护航
  • 对新人友爱
  • 能够减少许多代码

缺陷:

  • 全家桶,做的太多关于一些运用者来说是丧命缺陷,需求解决的 Bug 也多
  • “魔法”运用较多,脱离 Flutter 原本轨道
  • 侵略性极强

总的来说,GetX 很优异,他帮你都写好了许多东西,省去了开发者还要考虑怎么去组合和考虑的进程,从我个人的视点我不喜欢这种风格,可是它总归是能够协助你进步开发效率。

别的还有一个状况办理库 Mobx ,它库选用了和 GetX 相似的风格,尽管 Mobx 的知名度和关注度不像 GetX 那么高,可是它相同选用了隐式依靠的形式,某种含义上能够把 Mobx 看成是只要状况办理版本的 GetX

Flutter 工程化框架选择 — 状态管理何去何从

最后

经过上面共享的内容,相信我们关于选哪个状况办理结构应该有自己的了解了,仍是那句废话,选用什么计划和结构详细仍是取决于你的需求场景,不管是哪个结构目前都有坑和限制,要点仍是在于它未来是否持续保护,或许不保护了你自己能否持续保护下去

最后,假如你还有什么疑问,或许针对 Flutter 工程挑选上还有哪些茫然,欢迎留言谈论。