去年接手公司鸿蒙与Flutter跨端项目时,面对复杂的状态管理和路由跳转需求,我尝试了各种方案后最终选择了GetX。这个轻量级框架用200行代码替代了原先2000行的BLoC模板代码,让团队开发效率提升了3倍。GetX最吸引我的特点是其"All in One"的设计理念——用一套简洁的API解决了状态管理、依赖注入、路由导航等核心问题,特别适合需要同时兼顾鸿蒙和Flutter平台的开发者。
在鸿蒙生态中,虽然官方提供了ArkUI的状态管理机制,但在需要与Flutter共享业务逻辑的场景下,GetX展现出了独特的跨框架适配能力。我们可以在Flutter侧用GetX编写核心业务逻辑,再通过FFI或平台通道与鸿蒙原生层交互,实现真正的代码复用。这种架构下,GetX就像胶水一样粘合了两个平台的差异层。
GetX的响应式系统基于Dart的Stream机制,但做了极致优化。与BLoC需要手动管理StreamController不同,GetX通过Rxvar count = 0.obs时,实际上创建了一个RxInt对象,其内部维护了观察者列表:
dart复制class RxInt extends Rx<int> {
@override
int value;
// 当value变化时自动通知所有观察者
}
在鸿蒙侧,我们需要通过GetBuilder组件将ArkUI的组件与GetX状态绑定。实测发现,相比原生ArkUI的@State装饰器,GetX的更新粒度更细,能精确到具体变量变化时才触发重建。
GetX的路由导航在鸿蒙环境下需要特殊处理。常规的Get.to()在Flutter中直接工作,但在鸿蒙中我们需要封装一层平台通道:
dart复制Future<void> toHarmonyPage(String route) async {
if (Platform.isHarmony) {
await invokeHarmonyNative('navigate', {'route': route});
} else {
Get.toNamed(route);
}
}
这种设计使得业务代码可以统一使用Get.to(HomePage())这样的声明式API,底层自动处理平台差异。我们在实际项目中抽象出了HarmonyRouteMixin,通过注解处理器自动生成路由映射表。
下面是一个跨平台购物车的典型实现。首先定义响应式模型:
dart复制class CartItem {
final String id;
final String title;
final RxInt quantity;
final double price;
CartItem({
required this.id,
required this.title,
required int quantity,
required this.price,
}) : quantity = quantity.obs;
}
class CartService extends GetxService {
final RxList<CartItem> items = <CartItem>[].obs;
double get total => items.fold(0, (sum, item) => sum + item.price * item.quantity.value);
void addItem(CartItem newItem) {
final existing = items.firstWhereOrNull((item) => item.id == newItem.id);
existing?.quantity.value += newItem.quantity.value ?? items.add(newItem);
}
}
在鸿蒙页面中使用时,需要特别注意线程安全问题:
dart复制void buildCartItem(CartItem item) {
GetBuilder<CartService>(
builder: (controller) {
// 鸿蒙的Column组件需要特殊处理子项间距
return Column({
Text(item.title),
Row([
IconButton(onClick: () => item.quantity.value--),
Text('${item.quantity.value}'),
IconButton(onClick: () => item.quantity.value++),
])
});
}
);
}
GetBuilder的id参数限定刷新范围Get.delete释放资源,避免内存泄漏GetX的依赖注入系统可以无缝衔接鸿蒙的HAP包机制。我们设计了一个插件注册中心:
dart复制abstract class FeaturePlugin {
String get name;
void registerRoutes(GetPages pages);
void registerServices(GetIt getIt);
}
// 在鸿蒙入口模块
void main() {
runApp(MyApp([
PaymentPlugin(),
UserCenterPlugin(),
// 动态加载的HAP包插件
]));
}
class MyApp extends StatelessWidget {
final List<FeaturePlugin> plugins;
void onInit() {
plugins.forEach((plugin) {
plugin.registerRoutes(Get.routes);
plugin.registerServices(Get.find);
});
}
}
针对鸿蒙和Flutter不同的存储系统,我们封装了统一的持久层:
dart复制abstract class StorageService {
Future<void> save(String key, dynamic value);
dynamic read(String key);
}
// Flutter实现
class FlutterStorage extends StorageService {
final SharedPreferences _prefs = await SharedPreferences.getInstance();
// ...实现接口
}
// 鸿蒙实现
class HarmonyStorage extends StorageService {
final _prefs = ... // 调用鸿蒙Preferences接口
// ...实现接口
}
// 统一使用方式
final storage = Get.put<StorageService>(
Platform.isHarmony ? HarmonyStorage() : FlutterStorage()
);
在main()中配置日志过滤器:
dart复制void main() {
Get.config(
enableLog: true,
logWriterCallback: (text, {bool isError = false}) {
if (isError || Get.isLogEnable) {
// 在鸿蒙环境下输出到hilog
if (Platform.isHarmony) {
hilog.debug(0x0000, "GetX", text);
} else {
debugPrint(text);
}
}
}
);
}
在开发阶段添加内存监控:
dart复制class MemoryDebugger extends GetxService {
final Map<String, int> _instanceCount = {};
void trackInstance(Object obj) {
final key = obj.runtimeType.toString();
_instanceCount[key] = (_instanceCount[key] ?? 0) + 1;
if (_instanceCount[key]! > 20) {
Get.log('⚠️ Potential leak: $key count=${_instanceCount[key]}');
}
}
}
// 在Get.put时自动调用
extension MemoryTracking on GetInterface {
Future<S> putTracking<S>(S dependency) async {
Get.find<MemoryDebugger>().trackInstance(dependency);
return put(dependency);
}
}
我们团队采用的分阶段迁移方案:
Get.offAllNamed确保路由栈正确GetxController的生命周期方法PlatformViewLink混合原生鸿蒙组件时,需要特殊处理GetX上下文经过半年实践,我们的混合应用包体积减少了40%,首屏加载时间缩短了35%。GetX的简洁哲学确实在跨端开发中展现了独特优势,特别是在需要快速迭代的业务场景下。对于刚接触鸿蒙的Flutter开发者,我的建议是:先用GetX构建核心业务逻辑,再逐步处理平台特定实现,这样能最大限度保持代码的可移植性。