Flutter 应用开发中状态管理是重要的一环,目前成熟的状态管理插件有 provider,provider,getx 等,本文基于 getx 的使用及基本原理展开讨论,文末有具体工程示例链接;
1. GetX 的核心架构
GetX 是一个轻量级的状态管理、依赖注入和路由管理框架,它的核心目标------>
减少样板代码,最大化开发效率
从更新原理及工程整合上与 provider 及 bloc 的差异
| 维度 | Provider | BLoC | GetX |
|---|---|---|---|
| 是否依赖 context | 强 | 中 | ❌ 不需要 |
| 状态更新模型 | rebuild | event → state | 响应式 / 命令式 |
| 样板代码 | 少 | 多 | 极少 |
| 生命周期 | Widget 驱动 | BLoC 显式控制 | Route + SmartManagement |
| 工程整合度 | 低 | 中 | 高 |
1.1 响应式编程模型
GetX 的响应式编程基于观察者模式(Observer Pattern)实现。当一个被观察的变量(使用.obs标记)发生变化时,所有依赖该变量的 UI 组件都会自动重建。
内部实现上,GetX 使用了一个名为 GetStream的流(Stream)来管理状态变化。当可观察对象的值发生变化时,会触发流中的事件,从而通知所有监听者。
dart
// 简化的内部实现原理
class RxImpl<T> {
final _subject = GetStream<T>();
T get value => _subject.value;
set value(T val) {
_subject.add(val); // 触发流事件
}
}
1.2 依赖注入系统
GetX 的依赖注入系统基于服务定位器模式(Service Locator Pattern)。它维护了一个全局的依赖实例映射表,通过类型或标签来查找和注册依赖项。
dart
// 简化的内部实现原理
class GetInstance {
static final _singl = <String, dynamic>{};
void put<S>(S dependency, {String? tag}) {
_singl[_getKey(S, tag)] = dependency;
}
S find<S>({String? tag}) {
return _singl[_getKey(S, tag)] as S;
}
String _getKey(Type type, String? tag) => tag == null ? type.toString() : type.toString() + tag;
}
1.3 路由管理系统
GetX 的路由管理是对 Flutter 原生导航 API 的封装,它维护了一个全局的路由历史栈,并提供了更简洁的 API 来管理页面导航。
dart
// 简化的内部实现原理
class GetNavigation {
final _history = <GetPage>[];
Future<T?> to<T>(GetPage page) {
_history.add(page);
return Navigator.push(...); // 调用Flutter原生导航
}
void back() {
_history.removeLast();
Navigator.pop(...); // 调用Flutter原生导航
}
}
2. GetX 的工作原理
2.1 状态管理原理
简单状态管理
简单状态管理使用 GetBuilder和 update()方法:
- 当调用
update()时,GetX 会通知所有使用GetBuilder构建的与该控制器关联的 UI 组件进行重建 - 内部使用唯一 ID 来标识每个控制器实例,确保只有相关的 UI 组件会重建
dart
// 简化的内部实现原理
void update([List<String>? ids]) {
if (ids == null) {
// 通知所有监听该控制器的UI组件
_notifyAllListeners();
} else {
// 只通知特定ID的UI组件
_notifyListenersById(ids);
}
}
响应式状态管理
响应式状态管理使用 .obs 与 Obx()
-
当
.obs变量的值发生变化时,会触发内部的GetStream -
Obx()组件会监听这些流的变化,并在值变化时自动重建 UI -
GetX 使用了一个智能的差异算法,只重建依赖变化值的组件,而不是整个页面
dart
// 简化的内部实现原理
class Obx extends StatefulWidget {
@override
_ObxState createState() => _ObxState();
}
class _ObxState extends State<Obx> {
late StreamSubscription _subscription;
@override
void initState() {
super.initState();
// 订阅可观察变量的变化
_subscription = _getStream().listen((_) {
if (mounted) setState(() {}); // 触发UI重建
});
}
@override
Widget build(BuildContext context) {
// 构建UI时会访问可观察变量,从而建立依赖关系
return widget.builder();
}
}
2.2 依赖注入原理
GetX 的依赖注入系统支持多种注入方式:
-
常规注入 (
Get.put):立即创建实例并注册 -
懒加载注入 (
Get.lazyPut):只在首次使用时创建实例 -
异步注入 (
Get.putAsync):异步创建实例 -
一次性注入 (
Get.create):每次获取都创建新实例
内部实现上,GetX 使用工厂模式(Factory Pattern)来管理依赖的创建方式:
dart
// 简化的内部实现原理
void lazyPut<S>(InstanceBuilderCallback<S> builder) {
_factories[_getKey(S)] = builder; // 存储工厂函数
}
S find<S>() {
final key = _getKey(S);
if (_singl.containsKey(key)) {
return _singl[key]; // 返回已存在的实例
}
if (_factories.containsKey(key)) {
final instance = _factories[key](); // 调用工厂函数创建实例
_singl[key] = instance; // 缓存实例
return instance;
}
throw Exception('未找到依赖项');
}
2.3 路由管理原理
GetX 的路由管理系统在内部维护了一个页面堆栈,并提供了丰富的导航方法:
-
基本导航 :
Get.to()Get.back() -
命名路由 :
Get.toNamed()Get.offNamed() -
替换导航 :
Get.off()Get.offAll()
每个路由操作都会更新内部的页面堆栈,并调用 Flutter 原生的导航 API:
dart
// 简化的内部实现原理
Future<T?> toNamed<T>(String routeName, {dynamic arguments}) {
final route = _findRouteByName(routeName);
if (route != null) {
_currentRoute = route;
return Navigator.of(context).pushNamed(routeName, arguments: arguments);
}
throw Exception('未找到路由');
}
3. GetX 的优化机制
3.1 内存管理
GetX 提供了智能的内存管理机制:
-
自动释放:当控制器不再被使用时,默认会被自动释放
-
永久实例 :使用
permanent: true参数可以创建永久实例 -
智能实例 :使用
fenix: true参数可以在需要时重新创建已释放的实例
dart
// 自动释放机制简化实现
void _autoRelease() {
if (!_isPermanent && _getBuilderCount() == 0) {
_singl.remove(_getKey(this.runtimeType));
}
}
3.2 性能优化
GetX 在性能方面做了多项优化:
-
局部更新:只重建依赖变化数据的 UI 部分
-
懒加载:只在需要时创建依赖实例
-
按需构建 :使用
GetBuilderid 参数可以更精确地控制 UI 更新范围
dart
// 局部更新机制简化实现
void update([List<String>? ids]) {
if (ids == null) {
_notifyAllListeners();
} else {
// 只通知特定ID的监听器
for (final id in ids) {
_notifyListenersById(id);
}
}
}
工程示例
text
lib/
├── app/
│ ├── controllers/ # 控制器(状态管理)
│ ├── modules/ # 各功能模块的UI页面
│ ├── routes/ # 路由管理
│ ├── translations/ # 国际化翻译
│ └── bindings/ # 依赖注入绑定
└── main.dart # 应用入口