pubspec.yaml 文件:

 1`dependencies:
 2  get:`

1. 状态管理

状态管理其实就是管理应用的数据,在 get中也称为控制器,所有的数据都必须放在 继承自 GetController 的类中,才可以在视图中使用

第一步:创建 一个Controller

 1`import 'package:get/get.dart';
 2
 3/// 定义数据控制器
 4class HomeController extends GetxController {}`

第二步:在控制器中声明变量

 1`/// 定义数据控制器
 2class HomeController extends GetxController {
 3  // 使用 .obs 作为你值的后缀
 4  final name = "老汪".obs;
 5
 6  // 使用 Rx 和 Darts 泛型,Rx < type >
 7  final count = Rx<int>(0);
 8
 9  // 使用 Rx { Type }
10  final isLogged = RxBool(false);
11}`

第三步:在UI中使用变量

 1`import 'package:flutter/material.dart';
 2import 'package:getx_demo/page/home_controller.dart';
 3
 4class HomePage extends StatelessWidget {
 5  // 实例化控制器
 6  final controller = HomeController();
 7
 8  @override
 9  Widget build(BuildContext context) {
10    return Scaffold(
11      appBar: AppBar(
12        title: Text("状态管理"),
13        centerTitle: true,
14      ),
15      body: Container(
16        width: double.infinity,
17        child: Column(
18          crossAxisAlignment: CrossAxisAlignment.center,
19          children: [
20            Text('name: ${controller.name}'),
21            Text('count: ${controller.count}'),
22            Text('isLogged: ${controller.isLogged}'),
23            Divider(),
24            Text('循环items列表:'),
25            Row(
26              mainAxisAlignment: MainAxisAlignment.center,
27              children:
28                  controller.items.map((item) => Text("$item, ")).toList(),
29            )
30          ],
31        ),
32      ),
33    );
34  }
35}`

2. 声明“可观察的”变量

2.1 第一个是使用 Rx { Type }。

 1`final name = RxString('');
 2final isLogged = RxBool(false);
 3final count = RxInt(0);
 4final balance = RxDouble(0.0);
 5final items = RxList<String>([]);
 6final myMap = RxMap<String, int>({});`

2.2 第二种是使用 Rx 和 Darts 泛型,Rx < type >

 1`final name = Rx<string>('');
 2final isLogged = Rx<bool>(false);
 3final count = Rx<int>(0);
 4final balance = Rx<double>(0.0);
 5final number = Rx<num>(0)
 6final items = Rx<List<string>>([]);
 7final myMap = Rx<Map<string, int>>({});
 8
 9// 自定义类
10final user = Rx<User>();`

2.3 第三种方法更实用、更简单也是首选,就是把.obs 作为你的变量的后缀:

 1`final name = ''.obs;
 2final isLogged = false.obs;
 3final count = 0.obs;
 4final balance = 0.0.obs;
 5final number = 0.obs;
 6final items = <String>[].obs;
 7final myMap = <String, int>{}.obs;
 8
 9// Custom classes - it can be any class, literally
10final user = User().obs;`

3. 什么类型可被定义为的obs

你可以在 obs 上转换任何东西:

 1`import 'package:get/get.dart';
 2
 3class User {
 4  final name;
 5  final age;
 6  User({this.name, this.age});
 7}
 8
 9class Teacher {
10  final name = "李思思".obs;
11  final languer = "语文".obs;
12}
13
14/// 定义数据控制器
15class HomeController extends GetxController {
16  // 使用 .obs 作为你值的后缀
17  final name = "老汪".obs;
18
19  // 使用 Rx 和 Darts 泛型,Rx < type >
20  final count = Rx<int>(0);
21
22  // 使用 Rx { Type }
23  final isLogged = RxBool(false);
24
25  // 使用 .obs 作为你值的后缀
26  final items = <String>["flutter", "getx", "redux", "java"].obs;
27
28  // 自定义User类
29  final user = User(name: "Camila", age: 18).obs;
30
31  // 自定义teacher类
32  final teacher = Teacher();
33
34  // Map, 不响应的数据
35  final subjects = {"name": "语文", "desc": "超扫good"};
36}` 
37
38![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

4. 如何改变数据的值

第一步: 计数器案例

 1// 创建控制器
 2class HomeController extends GetxController {
 3  // 使用 Rx 和 Darts 泛型,Rx < type >
 4  final count = Rx<int>(0);
 5    
 6  // 每次点击增加1
 7  void increment() {
 8    print("++")
 9    // 必须使用 .value 修饰具体的值
10    this.count.value++;
11  }
12}

第二步: UI中使用,并添加点击事件

 1`class HomePage extends StatelessWidget {
 2  // 实例化控制器
 3  final controller = HomeController();
 4
 5  @override
 6  Widget build(BuildContext context) {
 7    return Scaffold(
 8      appBar: AppBar(
 9        title: Text("状态管理"),
10        centerTitle: true,
11      ),
12      body: Container(
13        width: double.infinity,
14        child: Column(
15          crossAxisAlignment: CrossAxisAlignment.center,
16          children: [
17            Text('数字类型: ${controller.count}'),
18            MaterialButton(
19              onPressed: () {
20                // 直接调用函数
21                controller.increment();
22              },
23              color: Colors.blue,
24              child: Text("change数字类型"),
25            )
26          ],
27        ),
28      ),
29    );
30  }
31}` 
32
33![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

此刻点击,按钮发送事件,控制台会打印数据,数据也确实改变了,但视图不会更新

5. 如何触发视图的更新

在Get中, 有两个不同的状态管理器: 简单的状态管理器(GetBuilder) 和 响应式的管理器(GetX/Obx),所以只有

使用这两个状态管理器修饰的值才会引起视图的更新

5.1 使用GetBuilder()更新

GetBuilder 的目标正是多状态控制。想象一下,你在一个购物车中添加了30种商品,你点击删除一种,同时列表被更新,价格被更新,购物车中的徽章被更新为一个更小的数字。这种类型的方法使得 GetBuilder 成为杀手,因为它将状态分组并同时更改它们,而不需要任何“计算逻辑”。创建 GetBuilder 时就考虑到了这种情况,因为对于状态的临时更改,可以使用 setState,而且不需要状态管理器

这样,如果您想要一个单独的控制器,您可以为它分配 id,或者使用 GetX。这取决于您,记住您拥有的小部件越多,GetX 的性能就越突出,而当状态发生多次更改时,GetBuilder 的性能应该更好。

优点:

只更新所需的小部件。

使用较少内存(接近0mb)的状态管理器

5.1.1 GetBuilder的使用

第一步: 创建控制器

 1`/// 定义数据控制器
 2class HomeController extends GetxController {
 3  // 注意,这里定义普通的值就行,不用使用.obs修饰
 4  int count = 0;
 5  // 需要手动调用update(),触发更新
 6  void increment() {
 7    count++;
 8    update(); 
 9  }
10}`

第二步:渲染视图并触发更新

 1`class HomePage extends StatelessWidget {
 2  @override
 3  Widget build(BuildContext context) {
 4    return Scaffold(
 5      appBar: AppBar(
 6        title: Text("状态管理"),
 7        centerTitle: true,
 8      ),
 9      body: Container(
10        width: double.infinity,
11        child: Column(
12          crossAxisAlignment: CrossAxisAlignment.center,
13          children: [
14            // 使用GetBuilder, 需要手动调用update()
15            GetBuilder<HomeController>(
16              init: HomeController(),
17              builder: (_) => Column(
18                children: [
19                  Text(
20                    '数字类型: ${_.count}',
21                    style: TextStyle(fontSize: 35),
22                  ),
23                  MaterialButton(
24                    onPressed: _.increment,
25                    color: Colors.blue,
26                    child: Text("++"),
27                  )
28                ],
29              ),
30            ),
31          ],
32        ),
33      ),
34    );
35  }
36}`

5.1.2 如果想用 GetBuilder 具体更新某个具体的小部件,你可以给它们分配唯一的 id:

第一步:添加id属性

 1`GetBuilder<HomeController>(
 2  id: "num",
 3  init: HomeController(),
 4  builder: (_) => Column(
 5    children: [
 6      Text(
 7        '数字类型: ${_.count}',
 8        style: TextStyle(fontSize: 35),
 9      ),
10      MaterialButton(
11        onPressed: _.increment,
12        color: Colors.blue,
13        child: Text("++"),
14      )
15    ],
16  ),
17)` 
18
19![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

第二步:update 时传入某个id属性

 1`// 直接按id更新
 2void increment() {
 3    count++;
 4    update(["num"]); 
 5}
 6
 7// 您还可以为更新添加条件, 当count 小于 5 时才更新
 8void increment() {
 9    count++;
10    update(["num"], count < 5); 
11}`

5.2 使用Obx()更新

第一步: 创建控制器

 1`/// 定义数据控制器
 2class HomeController extends GetxController {
 3  // 变量必须用final修饰
 4  final count = 0.obs;
 5  void increment() {
 6    count.value++;
 7  }
 8}`

第二步:渲染UI

 1`class HomePage extends StatelessWidget {
 2  // 实例化控制器
 3  final controller = HomeController();
 4
 5  @override
 6  Widget build(BuildContext context) {
 7    return Scaffold(
 8      appBar: AppBar(
 9        title: Text("状态管理"),
10        centerTitle: true,
11      ),
12      body: Container(
13        width: double.infinity,
14        child: Column(
15          crossAxisAlignment: CrossAxisAlignment.center,
16          children: [
17            // 使用Obx返回渲染的 UI widget
18            Obx(
19              () => Text(
20                '数字: ${controller.count}',
21                style: TextStyle(fontSize: 35),
22              ),
23            ),
24            // 添加点击事件
25            MaterialButton(
26              onPressed: controller.increment,
27              color: Colors.blue,
28              child: Text("++"),
29            )
30          ],
31        ),
32      ),
33    );
34  }
35}` 
36
37![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

在用户界面中,当你想要显示这个值并在值改变时更新屏幕时,只需要这样做:

注1:只有在 定义的变量的值发生变化时才会更改。

如果在一个 Obx 中有5多个 Rx (可观察的)变量,当它们中的任何一个发生变化时,它都会自动更新。

但如果我在一个类中有30个变量,当我更新一个时,它会更新该类中的所有变量吗?

并不会的,只有使用 Rx 变量的特定 Widget 才会更新,因此,当 Rx 变量改变它的值时,GetX 只更新屏幕


5.3 使用 GetX () 更新

用法同GetBuilder(), 但不能添加需要惟一的 id属性,

 1`class HomePage extends StatelessWidget {
 2  @override
 3  Widget build(BuildContext context) {
 4    return Scaffold(
 5      appBar: AppBar(
 6        title: Text("状态管理"),
 7        centerTitle: true,
 8      ),
 9      body: Container(
10        width: double.infinity,
11        child: Column(
12          crossAxisAlignment: CrossAxisAlignment.center,
13          children: [
14            GetX<HomeController>(
15              init: HomeController(),
16              builder: (_) => Column(
17                children: [
18                  Text(
19                    '数字类型: ${_.count}',
20                    style: TextStyle(fontSize: 35),
21                  ),
22                  MaterialButton(
23                    onPressed: _.increment,
24                    color: Colors.blue,
25                    child: Text("++"),
26                  )
27                ],
28              ),
29            ),
30          ],
31        ),
32      ),
33    );
34  }
35}`

6. GetxController生命周期钩子

  • onInit : 初次渲染完毕,可以在这里定义控制器(输入框,顶部选项卡,PageView等),调接口
  • onClose: 组件卸载时触发,清除定时器等
 1`class MyController extends GetxController {
 2    
 3  @override  
 4  onInit(){
 5      
 6  }    
 7  @override
 8  void onClose() {
 9    
10  }
11}`

6. 1 演示输入框配合控制器,

  • 调接口就不演示了,放到 写 GetConnect 这个文章里
 1`// 控制器
 2class HomeController extends GetxController {
 3  // 用户名控制器
 4  TextEditingController userNameController;
 5
 6  @override
 7  void onInit() {
 8    super.onInit();
 9    userNameController = TextEditingController();
10    print("渲染完成");
11  }
12
13  @override
14  void onClose() {
15    super.onClose();
16    print("close");
17  }
18}
19
20// UI 渲染
21class HomePage extends StatelessWidget {
22  // 实例化控制器
23  final controller = HomeController();
24
25  @override
26  Widget build(BuildContext context) {
27    return Scaffold(
28      appBar: AppBar(
29        title: Text("状态管理"),
30        centerTitle: true,
31      ),
32      body: Container(
33        width: double.infinity,
34        child: Column(
35          crossAxisAlignment: CrossAxisAlignment.center,
36          children: [
37            TextField(
38              controller: controller.userNameController,
39              decoration: InputDecoration(
40                hintText: "请输入用户名",
41              ),
42              onChanged: (val) {
43                print(val);
44              },
45            )
46          ],
47        ),
48      ),
49    );
50  }
51}` 
52
53![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

7. Get.find()

当有多个控制器时,指定使用某个具体的控制器

 1`// 现有 - HomeController, LoginController
 2Get.find<LoginController>()`

8. 混入状态 StateMixin (保存动态接口数据)

这个一般配合接口数据,在写 getConnect 一块时 说,可以简单看看

另一种处理 UI 状态的方法是使用 StateMixin < t > 。要实现它,可以使用 with 将 StateMixin < t > 添加到允许 t 模型的控制器中

 1`class Controller extends GetController with StateMixin<User>{}`

方法可以随时改变状态,只需以下方式传递数据和状态:

 1`change(data, status: RxStatus.success());`

允许这些状态:

 1`RxStatus.loading();
 2RxStatus.success();
 3RxStatus.empty();
 4RxStatus.error('message');`

要在 UI 中表示它,请使用:

 1`class OtherClass extends GetView<Controller> {
 2  @override
 3  Widget build(BuildContext context) {
 4    return Scaffold(
 5      body: controller.obx(
 6        (state)=>Text(state.name),
 7        
 8        onLoading: CustomLoadingIndicator(),
 9        onEmpty: Text('No data found'),
10       
11        onError: (error)=>Text(error),
12      ),
13    );
14}`

9. 内置函数工具类 Woker(一般事件发生时触发特定的回调。)

 1`/// 变量发出新值时,都会调用
 2ever(count1, (_) => print("$_ has been changed"));
 3
 4/// 在变量第一次被更改时才调用 
 5once(count1, (_) => print("$_ was changed once"));
 6
 7/// 防抖,连续点击多次,只执行一次,比如登录,搜索函数中非常有用
 8debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1));
 9
10/// 节流,如果用户在1秒内对一个变量进行了1000次更改,那么他只会在规定的计时器之后发送最后一次更改,默认为800毫秒
11interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));`

10. 对比 GetBuilder vs GetX vs Obx

GetBuilder 在 内存消耗 方面非常经济,而且几乎没有比他更经济的方法了,但是,GetBuilder 仍然是一个机械状态管理器,您需要手动调用 update () 才会更新视图

GetX 仍然比其他任何反应状态管理器更经济,但是它比 GetBuilder 消耗更多的内存

Obx 比 GetX 更经济,但是输给了 GetBuilder, 与 GetX 和 GetBuilder 不同,您不能在 Obx 中初始化控制器

但使用 Obx,您不需要编写控制器类型,可以从多个不同的控制器中听到更改,但是需要在此之前进行初始化

一劳永逸,使用Obx, 然后是GetX, 追求极致性能使用 GetBuilder

个人笔记记录 2021 ~ 2025