状态-Getx

发布时间 2023-04-21 10:16:17作者: cps666

原文地址 zhuanlan.zhihu.com

状态-Getx

残枫cps残枫cps

GetxController 生命周期

整个生命周期我们能够接入的方法就三个:

  • onInit:初始化 Controller,例如一些成员属性的初始化;
  • onReady:就绪后的业务处理,如异步操作、导航进入的参数处理等;
  • onClose:释放资源,避免内存泄露,同时也可以进行数据持久化。

GetBuilder 是一个 Widget 组件, 在 GetX 的状态管理中,GetBuilder 的主要作用是结合 GetxController 实现界面数据的更新。当调用 GetxController 的 update 方法时,GetBuilder 包裹的 Widget 就会刷新从而实现界面数据的更新。

局部更新

多种状态可以分别更新,不需要为每个状态创建一个类。

再添加一个变量:

  1. int _counter = 0;
  2. int get counter => _counter;
  3. String _name = "Lili";
  4. String get firstName => _name;
  5. void increment() {
  6. _counter++;
  7. _name = WordPair.random().asPascalCase;
  8. update(['counter']);
  9. }
  10. void changeName() {
  11. _counter++;
  12. _name = WordPair.random().asPascalCase;
  13. update(['name']);
  14. }

两个方法分别改变两个变量,但是注意update(['counter']里添加了 id 数组,这样就只更新这个 id 对应的GetBuilder:

  1. GetBuilder(
  2. id: 'counter',
  3. builder: (ctl) => Text(ctl.counter.toString()),
  4. ),
  5. SizedBox(
  6. height: 50,
  7. ),
  8. GetBuilder(
  9. id: 'name',
  10. builder: (ctl) => Text(ctl.firstName),
  11. ),

响应式刷新

我们都用过 StreamControllers ,然后以流的方式发送数据。在 GetX 可以实现同样的功能,并且实现起来只有几个单词,不需要为每个观察的对象创建一个 StreamController ,也不需要创建 StreamBuilder。

var name = '新衣';

下面简单的一个后缀就可以把一个变量变得可观察,变量每次改变的时候,使用它的小部件就会被更新:

var name = '新衣'.obs;

就这么简单,这个变量已经是响应式的了。然后通过 Obx 或者 GetX 包裹并使用响应式变量的控件,在变量改变的时候就会被更新:

Obx (() => Text (controller.name));

下面写个计算器的例子:

  1. final count1 = 0.obs;
  2. final count2 = 0.obs;

.obs就实现了一个被观察者,他们不再是 int 类型,而是 RxInt 类型。对应的小部件也不再是GetBuilder了,而是下面两种:

  1. GetX(
  2. builder: (_) {
  3. print("count1 rebuild");
  4. return Text(
  5. '${_.count1}',
  6. style: TextStyle(fontWeight: FontWeight.bold),
  7. );
  8. },
  9. ),
  10. Obx(() => Text(
  11. '${Get.find().count2}',
  12. style: TextStyle(fontWeight: FontWeight.bold),
  13. )),

因为是响应式,不再需要update,每次更改值,都自动刷新。但是更神奇的是,他们的运算和也是响应式的:

int get sum => count1.value + count2.value;

只要更新count1或者count2使用sum的小部件也会更改:

  1. Obx(() => Text(
  2. '${Get.find().sum}',
  3. style: TextStyle(fontWeight: FontWeight.bold),
  4. )),

setState

当调用setState后,所在Widget会进行重新渲染,这样便实现了页面上显示数据的更新。

下方代码中,点击按钮是否会触发页面上的数字变化?

class XXXState extends State<TestPage> {
  var click = 0;
  Widget w;

  @override
  void initState() {
    super.initState();
    w = Column(
      children: <Widget>[
        Text("${click}"),
        RaisedButton(
          child: Text("点击"),
          onPressed: () {
            click++;
            setState(() {});
          },
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: w,
    );
  }
} 

...

解答:不会变化,因为w变量中的组件,并没有重新实例化,所有w的状态一直都保持不变,组件一直保存在变量w中。

点击按钮确实会使当前组件重新渲染、会重新调用build,但是其中的子组件w,并没有重新实例化,其中的状态也没有发生任何改变