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)。

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui