flutter GetX 详解

GetX 是 Flutter 生态中非常流行的轻量级、高性能框架,它将状态管理、路由管理、依赖注入三大核心功能整合在一起,同时提供了大量实用工具。


一、GetX 三大核心功能

功能 说明 关键类/方法
状态管理 响应式编程,自动更新UI GetxController, Obx, GetX, Rx
路由管理 无需 BuildContext 的导航 Get.to(), Get.back(), Get.offAll()
依赖注入 自动管理 Controller 生命周期 Get.put(), Get.find(), Bindings

二、状态管理详解

1. 响应式状态(Reactive State)

GetX 使用 Rx 类型实现响应式编程,当数据变化时自动刷新 UI。

复制代码
import 'package:get/get.dart';

class CounterController extends GetxController {
  // 定义响应式变量
  var count = 0.obs;           // int 的响应式版本
  var name = 'Flutter'.obs;    // String 的响应式版本
  var items = <String>[].obs;  // List 的响应式版本
  
  void increment() => count++;
  void changeName(String newName) => name.value = newName;
}

2. 三种监听方式

方式一:Obx(最轻量,推荐)
复制代码
class HomePage extends StatelessWidget {
  final controller = Get.put(CounterController());
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        // Obx 只监听其内部使用的 Rx 变量
        child: Obx(() => Text(
          '点击次数: ${controller.count.value}',
          style: TextStyle(fontSize: 24),
        )),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}
方式二:GetX(监听整个 Controller)
复制代码
GetX<CounterController>(
  builder: (controller) {
    return Text('点击次数: ${controller.count.value}');
  },
)
方式三:GetBuilder(手动更新,性能最高)
复制代码
class CounterController extends GetxController {
  int count = 0;
  
  void increment() {
    count++;
    update(); // 手动触发更新,类似 notifyListeners()
  }
}

// UI 中使用
GetBuilder<CounterController>(
  builder: (controller) {
    return Text('点击次数: ${controller.count}');
  },
)

3. Workers(监听器)

Workers 用于监听 Rx 变量的变化并执行副作用:

复制代码
class UserController extends GetxController {
  final name = ''.obs;
  final age = 0.obs;
  
  @override
  void onInit() {
    super.onInit();
    
    // 每次变化都执行
    ever(name, (value) => print('名字变为: $value'));
    
    // 只执行一次
    once(age, (value) => print('年龄第一次变化: $value'));
    
    // 防抖(停止输入 1 秒后执行)
    debounce(name, (value) => print('搜索: $value'), time: Duration(seconds: 1));
    
    // 节流(每 2 秒最多执行一次)
    interval(count, (value) => print('计数: $value'), time: Duration(seconds: 2));
  }
}

三、路由管理

GetX 路由完全脱离 BuildContext,代码更简洁。

基础导航

复制代码
// 跳转到新页面
Get.to(HomePage());

// 返回上一页
Get.back();

// 替换当前页面(无法返回)
Get.off(HomePage());

// 清除所有页面并跳转(如登录后进入首页)
Get.offAll(HomePage());

// 跳转到命名路由
Get.toNamed('/home');

// 带参数跳转
Get.toNamed('/profile', arguments: {'id': 123, 'name': '张三'});

路由配置

复制代码
void main() {
  runApp(GetMaterialApp(
    initialRoute: '/',
    getPages: [
      GetPage(name: '/', page: () => SplashPage()),
      GetPage(name: '/home', page: () => HomePage()),
      GetPage(
        name: '/profile/:id',
        page: () => ProfilePage(),
        // 中间件(如登录验证)
        middlewares: [AuthMiddleware()],
        // 转场动画
        transition: Transition.cupertino,
      ),
    ],
  ));
}

接收参数

复制代码
class ProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取路由参数
    final id = Get.parameters['id'];
    final args = Get.arguments;
    
    return Scaffold(
      appBar: AppBar(title: Text('用户 $id')),
    );
  }
}

四、依赖注入(Bindings)

Bindings 用于将 Controller 与页面绑定,自动管理生命周期。

1. 基础使用

复制代码
class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => HomeController());
    Get.lazyPut(() => UserController());
  }
}

// 路由中绑定
GetPage(
  name: '/home',
  page: () => HomePage(),
  binding: HomeBinding(),
)

2. 依赖注入方式对比

复制代码
// 立即注入(应用启动时创建)
Get.put(Controller());

// 懒加载(第一次使用时创建,推荐)
Get.lazyPut(() => Controller());

// 异步注入(如需要网络请求初始化)
Get.putAsync(() async => await SharedPrefsController.init());

// 创建新实例(每次调用都新建)
Get.create(() => Controller());

3. 查找依赖

dart

复制代码
// 在任意位置获取 Controller
final controller = Get.find<HomeController>();

// 删除依赖(释放资源)
Get.delete<HomeController>();

五、Controller 生命周期

复制代码
class MyController extends GetxController {
  @override
  void onInit() {
    super.onInit();
    // 初始化数据、监听 Workers
  }
  
  @override
  void onReady() {
    super.onReady();
    // 首次渲染完成后调用(类似 initState 之后)
  }
  
  @override
  void onClose() {
    // 页面销毁时调用,释放资源、取消订阅
    super.onClose();
  }
}

六、实用工具

1. Snackbar(提示条)

复制代码
Get.snackbar(
  '操作成功',
  '数据已保存',
  snackPosition: SnackPosition.BOTTOM,
  backgroundColor: Colors.green,
  colorText: Colors.white,
  duration: Duration(seconds: 2),
);

2. Dialog(对话框)

复制代码
Get.defaultDialog(
  title: '确认删除',
  middleText: '此操作不可撤销',
  textConfirm: '删除',
  textCancel: '取消',
  confirmTextColor: Colors.white,
  onConfirm: () => Get.back(),
);

// 自定义 Dialog
Get.dialog(AlertDialog(...));

3. BottomSheet(底部弹

复制代码
Get.bottomSheet(
  Container(
    height: 200,
    color: Colors.white,
    child: Center(child: Text('底部内容')),
  ),
);

4. 主题切换

复制代码
// 切换深色/浅色模式
Get.changeTheme(Get.isDarkMode ? ThemeData.light() : ThemeData.dark());

// 监听系统主题
Get.changeThemeMode(ThemeMode.system);

5. 国际化(i18n)

复制代码
class Messages extends Translations {
  @override
  Map<String, Map<String, String>> get keys => {
    'zh_CN': {
      'hello': '你好',
      'welcome': '欢迎 @name',
    },
    'en_US': {
      'hello': 'Hello',
      'welcome': 'Welcome @name',
    },
  };
}

// 使用
Text('hello'.tr);                    // 你好
Text('welcome'.trParams({'name': '张三'})); // 欢迎 张三

七、完整实战示例

复制代码
// main.dart
void main() {
  runApp(GetMaterialApp(
    title: 'GetX Demo',
    initialRoute: '/',
    getPages: [
      GetPage(name: '/', page: () => LoginPage()),
      GetPage(
        name: '/home',
        page: () => HomePage(),
        binding: HomeBinding(),
      ),
    ],
  ));
}

// controllers/home_controller.dart
class HomeController extends GetxController {
  final tasks = <Task>[].obs;
  final isLoading = false.obs;
  
  @override
  void onInit() {
    fetchTasks();
    super.onInit();
  }
  
  void fetchTasks() async {
    isLoading.value = true;
    await Future.delayed(Duration(seconds: 1));
    tasks.addAll([
      Task(title: '学习 GetX', done: false),
      Task(title: '完成项目', done: false),
    ]);
    isLoading.value = false;
  }
  
  void toggleTask(int index) {
    tasks[index].done = !tasks[index].done;
    tasks.refresh(); // 刷新列表
  }
}

// bindings/home_binding.dart
class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => HomeController());
  }
}

// pages/home_page.dart
class HomePage extends StatelessWidget {
  final controller = Get.find<HomeController>();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('任务列表')),
      body: Obx(() {
        if (controller.isLoading.value) {
          return Center(child: CircularProgressIndicator());
        }
        return ListView.builder(
          itemCount: controller.tasks.length,
          itemBuilder: (context, index) {
            final task = controller.tasks[index];
            return ListTile(
              title: Text(
                task.title,
                style: TextStyle(
                  decoration: task.done ? TextDecoration.lineThrough : null,
                ),
              ),
              trailing: Checkbox(
                value: task.done,
                onChanged: (_) => controller.toggleTask(index),
              ),
            );
          },
        );
      }),
    );
  }
}

八、GetX vs 其他方案

特性 GetX Provider Riverpod BLoC
学习曲线 ⭐ 低 中 中 高
代码量 极少 较少 较少 较多
性能 高 高 高 高
路由管理 ✅ 内置 ❌ 需额外库 ❌ 需额外库 ❌ 需额外库
依赖注入 ✅ 内置 ❌ 需额外库 ✅ 内置 ❌ 需额外库
社区活跃度 高 高 高 高
官方推荐 非官方 非官方 非官方 非官方

九、注意事项

  1. 避免在 build 中调用 Get.put():应在页面顶部或 Binding 中注入

  2. Obx 嵌套问题:不要在 Obx 内部再创建 Obx 监听同一个 Controller,会导致重复监听

  3. Rx 集合的更新 :修改 List/Map 后需调用 .refresh() 或 .value = ...

  4. GetMaterialApp :使用 GetX 路由必须用 GetMaterialApp 替代 MaterialApp

  5. 与原生 Navigator 混用:尽量避免,可能导致路由栈混乱


GetX 的最大优势在于**"一站式"解决方案**------用一套框架同时解决状态、路由、依赖三大问题,代码简洁、学习成本低,非常适合中小型项目快速开发。对于大型项目,也可以只使用其中某个模块(如只用状态管理,路由仍用 Navigator 2.0)。

相关推荐
聚美智数几秒前
智能结构化识别-图片结构解析-图像结构化解析-照片结构化解析
android·java·数据库
mmsx5 小时前
Android 插件化架构:40 个 Gradle 模块的拆分、通信与共存
android·kotlin
mmsx5 小时前
Android 不改一行源码:用 AspectJ 做三类拦截
android·kotlin
TST-魚爷5 小时前
易视讯会议摄像头 + 全向麦克风实操讲解稿
android·电脑·钉钉·腾讯会议·zoom会议
嘟哩DuliDuli6 小时前
AI创作工作区的项目上下文与多模态任务边界
android·人工智能·安全·ai·软件工程
imDwAaY7 小时前
MySQL 存储引擎是什么?
android·数据库·mysql
Meteors.8 小时前
Android Compose学习02:基础组件与 Modifier
android·学习
其实防守也摸鱼9 小时前
存储管理:页面置换算法学习任务(测验题要求给出置换页面顺序,缺页次数,缺页率)
android·前端·数据库·学习·oracle·自动化
mmsx11 小时前
Android 地图上绘制 KML:解析、样式与渲染
android·xml
运行时异常11 小时前
【无标题】
android