跳转至

GetX 状态管理学习(初学通俗版)

核心目标:不用复杂概念,不用记一堆API,解决原生setState的痛点,看完就能上手写计数器、全局状态共享、跨页面传值,听完就懂、上手就会。


一、先搞懂:原生状态有什么麻烦?

你之前写页面状态用的原生写法是这样的:

int count = 0;

// 修改变量必须调用setState,否则UI不刷新
onPressed: (){
  setState((){
    count++;
  });
}

核心痛点(初学最直观的麻烦): 1. 只能在当前页面用,跨页面传值、共享状态非常麻烦(比如登录状态、购物车数量要在多个页面显示) 2. 业务逻辑和UI代码混在一起,页面写多了乱七八糟,维护困难 3. 每次改状态都要手动写setState,少写就不刷新,写多了重复代码 4. 控制器/工具类里没法直接改页面状态,必须传回调或者上下文


二、GetX 状态管理核心一句话

不用 setState!不用 Provider 那一堆复杂的上下文注入,三步就能实现响应式更新,页面、控制器随便改状态,自动刷新UI。

唯一前提(和路由一样): 已经把 MaterialApp 换成 GetMaterialApp(路由已经换过的话直接用,不用再改)。


三、3个核心概念(大白话解释,不用记原理)

不用管什么"响应式编程"、"单向数据流"这些虚的,就记住3个东西: 1. .obs(响应式变量):就是你要监听的变量,给普通变量后缀加个.obs,它一变就会自动通知UI刷新 2. GetxController(控制器):专门放状态变量和业务逻辑的类,和UI页面分离,逻辑可以复用,多个页面可以共用同一个控制器 3. Obx/GetBuilder(监听组件):UI里用它把要显示变量的地方包起来,只要变量变了,这块UI自动刷新,不用手动调用任何方法


四、2种最常用写法(必背,对应不同场景)

写法1:简单版(GetBuilder,新手首选,不用.obs,手动更新)

适合场景:简单页面状态、不需要自动实时更新的场景,写法最像原生,零学习成本。

3步直接套:

步骤1:写控制器(放状态和逻辑)

// 新建counter_controller.dart
import 'package:get/get.dart';

class CounterController extends GetxController {
  // 普通变量,不用加.obs
  int count = 0;

  // 写修改状态的方法
  void increment() {
    count++;
    // 手动通知UI刷新(就这一句,代替setState)
    update();
  }
}

步骤2:页面里注册控制器

// 在页面的build方法最顶部注册,注册一次全局可用
final CounterController controller = Get.put(CounterController());

步骤3:UI里用GetBuilder包起来,显示/修改状态

// 显示变量:用controller.count直接拿
GetBuilder<CounterController>(
  builder: (controller) => Text("当前计数:${controller.count}"),
)

// 修改状态:直接调用控制器方法,不用setState
ElevatedButton(
  onPressed: () => controller.increment(),
  child: Text("点我加1"),
)

写法2:响应式版(Obx + .obs,自动更新,更省事)

适合场景:需要实时自动更新的场景(比如实时显示播放进度、聊天消息、倒计时),不用手动调用update(),改了变量自动刷新。

3步直接套:

步骤1:写控制器(响应式变量加.obs)

// 新建counter_controller.dart
import 'package:get/get.dart';

class CounterController extends GetxController {
  // 给变量后缀加.obs,变成响应式变量
  RxInt count = 0.obs;
  // 其他类型示例:
  // RxBool isLogin = false.obs;
  // RxString userName = "".obs;
  // RxList<String> list = <String>[].obs;

  // 修改方法,不用调用update()
  void increment() {
    count++; // 直接改就行,自动通知UI刷新
  }
}

步骤2:页面注册控制器(和上面一样)

final CounterController controller = Get.put(CounterController());

步骤3:UI里用Obx包起来,自动刷新

// 显示变量:要用.value取响应式变量的值
Obx(() => Text("当前计数:${controller.count.value}"))

// 修改状态(和上面一样)
ElevatedButton(
  onPressed: () => controller.increment(),
  child: Text("点我加1"),
)

五、关键区别(最简单记忆)

写法 要不要.obs 要不要手动update() 适用场景
GetBuilder 不用 简单页面、不需要实时更新
Obx 不用 实时更新、复杂状态

初学建议:先练GetBuilder,写法和原生最像,几乎零学习成本,能搞定80%的场景。


六、全局状态共享(最实用功能,原生根本比不了)

GetX最大的优势:同一个控制器,多个页面可以共用,一处修改,所有地方自动更新!

比如做全局登录状态: 1. 写一个UserController,里面放isLoginuserName这些全局状态 2. 在main.dart里提前注册:Get.put(UserController()) 3. 任何页面、任何控制器里,只要写final UserController userController = Get.find();就能拿到这个全局控制器 4. 登录页改了userController.isLogin = true.obs,所有用到这个变量的页面(首页、我的页面)自动更新状态,不用传值、不用通知、不用回调!

示例代码(全局登录状态):

// 1. 全局控制器
class UserController extends GetxController {
  RxBool isLogin = false.obs;
  RxString userName = "未登录".obs;

  void login(String name) {
    userName.value = name;
    isLogin.value = true;
  }

  void logout() {
    userName.value = "未登录";
    isLogin.value = false;
  }
}

// 2. main.dart里提前注册
void main() {
  Get.put(UserController()); // 全局注册一次
  runApp(GetMaterialApp(home: LoginPage()));
}

// 3. 登录页调用
final UserController userController = Get.find();
userController.login("张三"); // 登录,修改全局状态

// 4. 我的页面直接用
Obx(() => Text("当前用户:${userController.userName.value}"))
// 自动显示"张三",不用传任何参数!

七、原生 vs GetX 状态管理对比

原生写法(麻烦)

// 页面内定义变量
int count = 0;

// 必须写setState,只能当前页面用
ElevatedButton(
  onPressed: (){
    setState((){
      count++;
    });
  },
  child: Text("${count}"),
)
// 跨页面共享?要写一堆传值、回调、通知,新手根本搞不定

GetX写法(简单)

// 控制器里定义,全应用通用
var count = 0.obs;

// 改状态不用setState,任何地方都能改
onPressed: () => count++,

// UI自动刷新,不用任何额外代码
Obx(() => Text("${count.value}"))

八、和你之前的项目结合(直接套用)

结合你之前的Vexfy音乐播放器项目,直接套用: 1. 写PlayerController继承GetxController,里面放playStatus(播放/暂停)、currentSong(当前歌曲)、progress(播放进度)这些状态 2. 页面里注册控制器,播放页、列表页、底部播放栏都用Get.find()拿到同一个控制器 3. 播放页点暂停,修改playStatus,底部播放栏自动刷新显示暂停状态,不用任何传值 4. 列表页点歌曲,修改currentSong,播放页自动更新歌曲信息,完全不用跨页面传参


补充说明(初学必看)

  1. 前提:已经在pubspec.yaml引入GetX依赖,已经把MaterialApp换成GetMaterialApp
  2. 控制器注册一次就够,不用重复注册,Get.put()注册,Get.find()获取,全应用通用
  3. 不用记复杂的API,先练熟上面2种基础写法,就能搞定90%的业务场景,什么永久控制器、绑定、依赖注入这些进阶功能以后再学
  4. 状态更新是局部刷新,只有包在Obx/GetBuilder里的UI会更新,比setState全页面刷新性能好很多