Flutter 入门与实战(八十三):GetX 状态管理怎么用,看这一篇就够了!

5,846 阅读5分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

GetX 从前到后我们也写了10多篇了,本篇对 GetX 状态管理部分的用法做一下总结,在实际开发过程中可以根据自身需要针对性的选择具体的用法。

简单状态管理 GetBuilder

GetBuilder 最大的好处是简单易用,尤其是对于从 Proivider 迁移过来的时候,代码改动量是很小的。编写的过程如下:

  • 编写 Controller 代码,在 VSCode 里 安装了 GetX Snippets 插件后可以使用 get controller快速插入Controller 代码模板。
  • 将使用到状态对象的 Widget 使用 GetBuilder 包裹起来,如下所示:
Widget build(BuildContext context) {
  return GetBuilder<CounterController>(
    // 初始化 Controller
    init: Controller(),
    // 在 builder里返回具体的 Widget
    builder: (controller) => XXXWidget(),
  );
}
  • 在引用状态对象的时候,直接引用builder参数中的controller即可。
  • 在完成更新状态对象的时候,手动调用一下 update 方法。注意,如果想定向更新,可以在 update 方法里插入一个 数组,这样只有GetBuilder 指定的id 在该数据组中才会更新。具体示例可以参考:Flutter 入门与实战(七十五):模拟红绿灯来看GetX的定向刷新
  • 如果一个 Controller 需要被多个不在同一组件树的Widget 使用,可以在 Controller 中定义一个静态属性使用 Get.find()获取状态对象或直接使用Get<T>.find()。之所以能够这么用是因为在 GetBuilder 初始化的时候将当前的状态对象放入到容器中了,具体大家可以看 GetBuilder 的源码实现。
static CounterController get to => Get.find();

实际上 GetBuilder是一个 StatefulWidget 的子类,在 update 被调用的时候,会调用builder参数的方法来刷新对应的组件。

GetxController具有自己生命周期,我们可以在不同的生命周期处理不同的业务,从而无需再引入 StatefulWidget 来管理生命周期了。可以参考:Flutter 入门与实战(七十四):GetxController 的生命周期详解

响应式状态管理GetX

GetBuilder 相比,响应式状态管理相当于实现了状态对象的绑定,只要状态对象发生了改变,依赖状态对象的组件会自动刷新,而不需要手动调用 upade 刷新,这会使得我们的代码更为简洁。GetX 实现响应的方式是定义了一个 Rx<T>的扩展(也可以使用 T.obs),当 Rx<T>对象的值变化的时候会通知 GetX<Controller>刷新,从而调用 GetX<Controller>的 builder 参数重新构建组件。具体示例可以看参考:Flutter 入门与实战(七十六):GetX 响应式状态管理简介

还有一种更简洁的用法,那就是 Obx,但是这种方式有个缺陷那就是状态对象 GetxController的生命周期函数不会被调用,更适用于简单的组件,性能当然也会更高些。

class CounterController extends GetxController {
  var _counter = 0.obs;

  static CounterController get to => Get.find();

  get counter => _counter.value;

  void increment() {
    _counter.value++;
  }
}

class CounterPage extends StatelessWidget {
  CounterPage({Key? key}) : super(key: key);
  final CounterController controller = CounterController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GetX计数器'),
      ),
      body: Center(
        child: Obx(() => Text('${controller.counter}')),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          controller.increment();
        },
      ),
    );
  }
}

混入页面状态StateMixin

使用 StateMixin 最大的好处是让我们的页面结构更优雅,当状态改变的时候调用 change 方法通知界面刷新,并且携带了一个状态。而这个状态可以自动切换不同状态对应的组件,从而避免了我们自己写一大堆的if...elseswitch 语句,组件构建的需要使用 controller.obx 包裹,并且页面需要继承GetView<PersonalMixinController>,代码如下所示,具体可以参考:Flutter 入门与实战(八十):使用GetX构建更优雅的页面结构

class PersonalHomePageMixin extends GetView<PersonalMixinController> {
  PersonalHomePageMixin({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return controller.obx(
      (personalEntity) => _PersonalHomePage(personalProfile: personalEntity!),
      onLoading: Center(
        child: CircularProgressIndicator(),
      ),
      onError: (error) => Center(
        child: Text(error!),
      ),
      onEmpty: Center(
        child: Text('暂无数据'),
      ),
    );
  }
}

四种方式的比较

官方对于这四种方式(Obx 也算一种)给出了优劣说明:

  • GetBuilder 消耗的内存最小,性能最优,当然代码可维护性来说就会牺牲一点,毕竟需要手动调用 update
  • Obx 的性能次之,优势是可以同时监听多个 Controller 的状态对象变化。缺点是 Controller 没有生命周期函数,而且 Controller 需要在 Obx 之外先初始化(这个倒问题不大,可以通过容器解决)。
  • GetX 更贴近实际项目一些,通过响应式的状态管理使得代码的可维护性更高。当然性能上会有些许损失。
  • StateMixin 更像是一个粘合剂,将页面的数据状态和对象粘合起来,然后简化我们构建不同状态页面的代码结构。性能上是最低的,当然这个性能差别在很多时候是体现不出来的。

至于具体怎么选择,看项目实际需要吧。

总结

本篇对 GetX 的几种状态管理用法进行了对比总结,可以看到,在状态管理方式上,GetX 提供了多样化的选择,好处是我们可以根据自己的需要自由选择。当然缺陷也是有的,多样化之后意味着同一个工程可能出现多种方式,这对代码结构的统一上不太方便。因此,实际开发中最好是约定好使用其中的1-2种方式。关于 GetX,网上的评价大多数是好评,在 pub 上的流行度也达到了99%,GitHub上目前超过了4.6k 的 star,整体来说用于生产是没问题的。当然,它也有一定的缺陷,下面一篇我们会结合一篇国外的文章客观地看一下 GetX 的缺陷。

我是岛上码农,微信公众号同名,这是Flutter 入门与实战的专栏文章,提供体系化的 Flutter 学习文章。对应源码请看这里:Flutter 入门与实战专栏源码。如有问题可以加本人微信交流,微信号:island-coder

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!