首页/文章/flutter

Getx - 如何使用状态管理数据_rxbool

2023-03-15
20427 分钟
...

pubspec.yaml 文件:

`dependencies:
  get:`

1. 状态管理

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

第一步:创建 一个Controller

`import 'package:get/get.dart';

/// 定义数据控制器
class HomeController extends GetxController {}`

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

`/// 定义数据控制器
class HomeController extends GetxController {
  // 使用 .obs 作为你值的后缀
  final name = "老汪".obs;

  // 使用 Rx 和 Darts 泛型,Rx < type >
  final count = Rx<int>(0);

  // 使用 Rx { Type }
  final isLogged = RxBool(false);
}`

第三步:在UI中使用变量

`import 'package:flutter/material.dart';
import 'package:getx_demo/page/home_controller.dart';

class HomePage extends StatelessWidget {
  // 实例化控制器
  final controller = HomeController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
        centerTitle: true,
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text('name: ${controller.name}'),
            Text('count: ${controller.count}'),
            Text('isLogged: ${controller.isLogged}'),
            Divider(),
            Text('循环items列表:'),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children:
                  controller.items.map((item) => Text("$item, ")).toList(),
            )
          ],
        ),
      ),
    );
  }
}`

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

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

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

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

`final name = Rx<string>('');
final isLogged = Rx<bool>(false);
final count = Rx<int>(0);
final balance = Rx<double>(0.0);
final number = Rx<num>(0)
final items = Rx<List<string>>([]);
final myMap = Rx<Map<string, int>>({});

// 自定义类
final user = Rx<User>();`

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

`final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;

// Custom classes - it can be any class, literally
final user = User().obs;`

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

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

`import 'package:get/get.dart';

class User {
  final name;
  final age;
  User({this.name, this.age});
}

class Teacher {
  final name = "李思思".obs;
  final languer = "语文".obs;
}

/// 定义数据控制器
class HomeController extends GetxController {
  // 使用 .obs 作为你值的后缀
  final name = "老汪".obs;

  // 使用 Rx 和 Darts 泛型,Rx < type >
  final count = Rx<int>(0);

  // 使用 Rx { Type }
  final isLogged = RxBool(false);

  // 使用 .obs 作为你值的后缀
  final items = <String>["flutter", "getx", "redux", "java"].obs;

  // 自定义User类
  final user = User(name: "Camila", age: 18).obs;

  // 自定义teacher类
  final teacher = Teacher();

  // Map, 不响应的数据
  final subjects = {"name": "语文", "desc": "超扫good"};
}` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

4. 如何改变数据的值

第一步: 计数器案例

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

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

`class HomePage extends StatelessWidget {
  // 实例化控制器
  final controller = HomeController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
        centerTitle: true,
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text('数字类型: ${controller.count}'),
            MaterialButton(
              onPressed: () {
                // 直接调用函数
                controller.increment();
              },
              color: Colors.blue,
              child: Text("change数字类型"),
            )
          ],
        ),
      ),
    );
  }
}` 

![](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的使用

第一步: 创建控制器

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

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

`class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
        centerTitle: true,
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            // 使用GetBuilder, 需要手动调用update()
            GetBuilder<HomeController>(
              init: HomeController(),
              builder: (_) => Column(
                children: [
                  Text(
                    '数字类型: ${_.count}',
                    style: TextStyle(fontSize: 35),
                  ),
                  MaterialButton(
                    onPressed: _.increment,
                    color: Colors.blue,
                    child: Text("++"),
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}`

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

第一步:添加id属性

`GetBuilder<HomeController>(
  id: "num",
  init: HomeController(),
  builder: (_) => Column(
    children: [
      Text(
        '数字类型: ${_.count}',
        style: TextStyle(fontSize: 35),
      ),
      MaterialButton(
        onPressed: _.increment,
        color: Colors.blue,
        child: Text("++"),
      )
    ],
  ),
)` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

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

`// 直接按id更新
void increment() {
    count++;
    update(["num"]); 
}

// 您还可以为更新添加条件, 当count 小于 5 时才更新
void increment() {
    count++;
    update(["num"], count < 5); 
}`

5.2 使用Obx()更新

第一步: 创建控制器

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

第二步:渲染UI

`class HomePage extends StatelessWidget {
  // 实例化控制器
  final controller = HomeController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
        centerTitle: true,
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            // 使用Obx返回渲染的 UI widget
            Obx(
              () => Text(
                '数字: ${controller.count}',
                style: TextStyle(fontSize: 35),
              ),
            ),
            // 添加点击事件
            MaterialButton(
              onPressed: controller.increment,
              color: Colors.blue,
              child: Text("++"),
            )
          ],
        ),
      ),
    );
  }
}` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

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

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

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

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

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


5.3 使用 GetX () 更新

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

`class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
        centerTitle: true,
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            GetX<HomeController>(
              init: HomeController(),
              builder: (_) => Column(
                children: [
                  Text(
                    '数字类型: ${_.count}',
                    style: TextStyle(fontSize: 35),
                  ),
                  MaterialButton(
                    onPressed: _.increment,
                    color: Colors.blue,
                    child: Text("++"),
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}`

6. GetxController生命周期钩子

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

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

  • 调接口就不演示了,放到 写 GetConnect 这个文章里
`// 控制器
class HomeController extends GetxController {
  // 用户名控制器
  TextEditingController userNameController;

  @override
  void onInit() {
    super.onInit();
    userNameController = TextEditingController();
    print("渲染完成");
  }

  @override
  void onClose() {
    super.onClose();
    print("close");
  }
}

// UI 渲染
class HomePage extends StatelessWidget {
  // 实例化控制器
  final controller = HomeController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("状态管理"),
        centerTitle: true,
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            TextField(
              controller: controller.userNameController,
              decoration: InputDecoration(
                hintText: "请输入用户名",
              ),
              onChanged: (val) {
                print(val);
              },
            )
          ],
        ),
      ),
    );
  }
}` 

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

7. Get.find()

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

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

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

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

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

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

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

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

允许这些状态:

`RxStatus.loading();
RxStatus.success();
RxStatus.empty();
RxStatus.error('message');`

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

`class OtherClass extends GetView<Controller> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: controller.obx(
        (state)=>Text(state.name),
        
        onLoading: CustomLoadingIndicator(),
        onEmpty: Text('No data found'),
       
        onError: (error)=>Text(error),
      ),
    );
}`

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

`/// 变量发出新值时,都会调用
ever(count1, (_) => print("$_ has been changed"));

/// 在变量第一次被更改时才调用 
once(count1, (_) => print("$_ was changed once"));

/// 防抖,连续点击多次,只执行一次,比如登录,搜索函数中非常有用
debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1));

/// 节流,如果用户在1秒内对一个变量进行了1000次更改,那么他只会在规定的计时器之后发送最后一次更改,默认为800毫秒
interval(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

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
flutter2026-07-01
Dart 入门回顾
1\. Dart 是什么 Dart 是一门类型安全、支持面向对象、支持异步编程的语言。它的语法和 JavaScript、TypeScript、Java、C# 都有一些相似之处。 Dart 常见使用场景: Flutter 跨平台应用开发 命令行工具 Web 应用 服务端接口或脚本 作为学习现代类型语言的入口 Dart 的几个核心特点: 静态类型:变量、函数返回值、参数都有类型。 类型推断:很多时候可以用 ,让 Dart 自动推断类型。 空...
学习
flutter2026-07-01
Flutter 常用 Widget 入门
Flutter 的核心思想是:一切皆 Widget。文字、图片、按钮、页面结构、布局、间距、滚动、动画、手势,几乎都由 Widget 组合出来。 1\. Widget 先分成几类理解 | 类别 | 常用 Widget | 解决什么问题 | | | | | | 应用入口 | 、 | 搭建应用外壳、主题、路由 | | 页面骨架 | 、 、 | 标准页面结构 | | 基础显示 | 、 、 | 显示文字、图标、图片 | | 布局容器 | 、 、...
学习
flutter2024-11-21
在 Flutter 中使用 webview_flutter 4.0
1. 2. ,已入选 3. 4. 本文是第 4 篇,定位是新手入门,介绍和演示 webview 的基础用法。最后还介绍了事件处理的技巧。因为是补写的,所以本来应该首发的却发在最后了。 环境准备已经在 说过了,不再赘述。既然是新手入门,就会本着详尽的原则,而且会多配示例。 获取页面信息 获取页面 title 核心方法:controller.getTitle 完整示例,放在 main.dart 就能运行。运行示例,点击获取 title 的按...
学习
flutter2024-11-06
flutter android端运行报错Namespace not specified. Specify a namespace in the module‘s build file
在使用flutterSDK 3.24之后发现新建项目,项目默认都是基于AGP8了,由于 AGP 开始强制要求 namespace 配置,不仅仅是主工程,也包括第三方库都强制要求 namespace 。但是我们在引入第三方库的时候会发现部分库没能及时的去做相关配置,这也就导致了我们会出现标题错误: 出现这个问题,我们可能会通过去找到本地缓存的第三方库代码去修改它的build.gradle和AndroidManifest.xml来解决缺失...
学习
flutter2024-11-03
Flutter中如何实现APP升级功能背景
背景 每个App应用中一定会包含的功能 ,App的运行平台不同实现升级功能的方式也就不同,基本分类如下所示。本文主要聚焦在使用Flutter框架开发的应用在安卓系统内如何更新,以及所涉及要点梳理。 IOS系统 Andriod系统 官网下载 各类应用市场 (本文聚焦点) 功能清单(按步骤) UpgradeCard组件(展示升级内容) 进行新旧版本对比判断是否需要更新 下载更新然后安装应用 UpgradeCard组件 组件需要包含基本标题、...
学习
flutter2024-11-03
Flutter应用内更新App版本使用flutter_downloader而非ota_update
做当前App应用内更新的前提:用户可以在App更新的时候还可以使用软件,不能让他一直等待下载,关闭下载组件后,打开组件还能继续看到他的进度,并且用户锁屏或者短暂退出APP后需要保证任务不能总是挂掉,这里没有用到保活,而是需要用到生命周期去让他暂停和恢复,所以当前app还要有一个全局管理类保存任务id。UI图在最后 (插件文档说明可以通知栏显示,但是我用的这个版本在100%下完后总是failed,而不是complete,就不会很友好,后面...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录