GetX:响应式、路由与依赖注入全家桶
mediumfluttergetxobxrxget-putnamed-routegetxcontroller
GetX 是什么?
GetX 是一个集状态管理、路由导航、依赖注入于一身的 Flutter 框架,以极低的样板代码著称。但因为功能过于集中,在大型团队中存在争议。
flutter pub add get
状态管理
GetX 提供两种状态管理方式:
反应式(Rx / Obx)
将变量包装为 Rx 类型,UI 用 Obx 监听:
class CounterController extends GetxController {
// .obs 将普通变量转为 Rx(可观察)
final count = 0.obs; // RxInt
final name = ''.obs; // RxString
final isLoading = false.obs; // RxBool
final users = <User>[].obs; // RxList<User>
void increment() => count++; // .value 自动更新,UI 自动刷新
void setName(String n) => name.value = n;
@override
void onInit() {
super.onInit();
// 监听变化(副作用)
ever(count, (value) => print('count changed to $value'));
}
}
// UI
class CounterPage extends StatelessWidget {
final ctrl = Get.put(CounterController()); // 注册+获取
@override
Widget build(BuildContext context) {
return Scaffold(
body: Obx(() => Text('${ctrl.count}')), // 只有这里 rebuild
floatingActionButton: FloatingActionButton(
onPressed: ctrl.increment,
child: const Icon(Icons.add),
),
);
}
}
简单状态(GetBuilder / update())
不需要 Rx,适合不需要细粒度响应的场景:
class SettingsController extends GetxController {
bool isDarkMode = false;
void toggleTheme() {
isDarkMode = !isDarkMode;
update(); // 触发绑定的 GetBuilder 重建
}
}
GetBuilder<SettingsController>(
builder: (ctrl) => Switch(
value: ctrl.isDarkMode,
onChanged: (_) => ctrl.toggleTheme(),
),
)
路由导航
GetX 路由不需要 BuildContext:
// 在 MaterialApp 替换为 GetMaterialApp
void main() => runApp(GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => const HomePage()),
GetPage(name: '/profile', page: () => const ProfilePage()),
GetPage(
name: '/detail/:id',
page: () => const DetailPage(),
binding: DetailBinding(), // 依赖绑定
),
],
));
// 导航(无需 context)
Get.toNamed('/profile'); // 推入
Get.offNamed('/home'); // 替换(无法返回)
Get.offAllNamed('/login'); // 清空栈并推入
Get.back(); // 返回
Get.back(result: 'some_data'); // 带返回值
// 参数传递
Get.toNamed('/detail/42', arguments: {'extra': 'data'});
// 在目标页获取
final id = Get.parameters['id']; // 路由参数
final extra = Get.arguments['extra']; // 额外参数
依赖注入
// 注册(put 立即创建,lazyPut 懒创建)
Get.put(UserController());
Get.lazyPut(() => UserController());
Get.putAsync(() async {
final prefs = await SharedPreferences.getInstance();
return SettingsController(prefs);
});
// 获取(任意位置,无需 context)
final ctrl = Get.find<UserController>();
// BindingsBuilder:将依赖绑定到路由生命周期
class DetailBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => DetailController());
}
}
// 绑定到路由后,离开页面自动 dispose Controller
GetxController 生命周期
class MyController extends GetxController {
@override
void onInit() {
super.onInit();
// 类似 initState,Controller 创建时调用
}
@override
void onReady() {
super.onReady();
// 第一帧渲染完成后调用(可以安全访问 UI)
}
@override
void onClose() {
// 类似 dispose,路由退出或 Delete 时调用
super.onClose();
}
}
GetX 争议
优点:
- 极少样板代码,快速开发
- 无需 BuildContext(路由、DI 任意位置调用)
- 文档完善,社区活跃
缺点:
- 功能过于集中,难以按需引入
- 魔法(magic)太多,调试困难
- 不符合 Flutter 官方推荐的数据流模式
- 大型团队可维护性存疑
- 路由不支持 Navigator 2.0 的声明式特性
建议:
- 个人项目、快速原型:适合使用 GetX
- 中大型团队项目:优先考虑 Provider + go_router 或 Riverpod
核心架构问题
Q:Get.find 和 Get.put 的区别?
Get.put 注册并立即创建实例(也可以获取);Get.find 获取已注册的实例(如果没有注册会抛出异常)。
Q:Obx 和 GetBuilder 的区别?
Obx 使用 Rx 变量,自动精细追踪变化(只有用到的变量变化时才重建);GetBuilder 使用普通变量 + update() 手动触发,类似 setState,但可以跨 Widget。