良好的状态管理不仅关注数据流,还需要正确处理控制器的初始化、销毁与生命周期事件,避免内存泄漏。
一、控制器封装(Controller)
1.1 通用控制器基类
dart
// 定义通用控制器接口
abstract class BaseController {
void onInit();
void onDispose();
}
// 带加载/错误状态的控制器基类
abstract class AsyncController<T> extends ChangeNotifier {
T? _data;
String? _errorMessage;
bool _isLoading = false;
T? get data => _data;
String? get errorMessage => _errorMessage;
bool get isLoading => _isLoading;
bool get hasError => _errorMessage != null;
bool get hasData => _data != null;
Future<void> load() async {
_isLoading = true;
_errorMessage = null;
notifyListeners();
try {
_data = await fetchData();
} catch (e) {
_errorMessage = e.toString();
} finally {
_isLoading = false;
notifyListeners();
}
}
// 子类实现具体数据获取逻辑
Future<T> fetchData();
void refresh() => load();
}
1.2 业务控制器实现
dart
class ProductListController extends AsyncController<List<Product>> {
final ProductRepository _repository;
String _searchQuery = '';
ProductCategory? _selectedCategory;
ProductListController(this._repository);
String get searchQuery => _searchQuery;
ProductCategory? get selectedCategory => _selectedCategory;
@override
Future<List<Product>> fetchData() async {
return await _repository.fetchProducts(
query: _searchQuery,
category: _selectedCategory,
);
}
void updateSearchQuery(String query) {
_searchQuery = query;
// 防抖:延迟500ms再请求
_debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), load);
}
void filterByCategory(ProductCategory? category) {
_selectedCategory = category;
notifyListeners();
load();
}
Timer? _debounce;
@override
void dispose() {
_debounce?.cancel();
super.dispose();
}
}
二、生命周期事件(GetX 风格)
2.1 GetxController 生命周期
dart
class OrderController extends GetxController {
final RxList<Order> orders = <Order>[].obs;
StreamSubscription? _orderSubscription;
Timer? _pollingTimer;
// ① 控制器首次注入时调用(类似 initState)
@override
void onInit() {
super.onInit();
_loadInitialOrders();
_startOrderTracking();
_setupEverListeners();
}
// ② 在 Widget 树中渲染完成后调用
@override
void onReady() {
super.onReady();
// 适合做需要 UI 就绪后才能执行的操作
// 如:展示欢迎弹窗
}
// ③ 控制器销毁时调用(类似 dispose)
@override
void onClose() {
_orderSubscription?.cancel();
_pollingTimer?.cancel();
super.onClose();
}
void _setupEverListeners() {
// ever:每次变化都触发
ever(orders, (_) => _updateBadgeCount());
// once:只触发一次
once(orders, (_) => _showFirstOrderHint());
// debounce:防抖
debounce(orders, (_) => _saveToLocal(), time: const Duration(seconds: 1));
// interval:节流
interval(orders, (_) => _syncToServer(), time: const Duration(seconds: 3));
}
void _startOrderTracking() {
_orderSubscription = OrderService.orderStream.listen(
(order) => orders.add(order),
);
}
void _loadInitialOrders() async {
final data = await OrderRepository.fetchAll();
orders.assignAll(data);
}
void _updateBadgeCount() {
// 更新应用角标
}
}
2.2 多控制器协作
dart
class CheckoutController extends GetxController {
// 依赖其他控制器
final cartController = Get.find<CartController>();
final userController = Get.find<UserController>();
final paymentController = Get.find<PaymentController>();
final RxBool isProcessing = false.obs;
final Rx<OrderResult?> orderResult = Rx<OrderResult?>(null);
Future<void> placeOrder() async {
if (cartController.items.isEmpty) {
Get.snackbar('提示', '购物车为空');
return;
}
isProcessing.value = true;
try {
final result = await OrderService.createOrder(
userId: userController.currentUser.value!.id,
items: cartController.items,
paymentMethod: paymentController.selectedMethod.value,
);
orderResult.value = result;
cartController.clear(); // 清空购物车
Get.toNamed('/order-success', arguments: result);
} catch (e) {
Get.snackbar('下单失败', e.toString());
} finally {
isProcessing.value = false;
}
}
}
三、Stream 状态同步
3.1 Riverpod + Stream
dart
// 实时监听订单状态
@riverpod
Stream<List<Order>> activeOrders(ActiveOrdersRef ref) {
final userId = ref.watch(currentUserProvider).value?.id;
if (userId == null) return const Stream.empty();
// 使用 ref.onDispose 清理资源
final subscription = OrderService.watchOrders(userId);
ref.onDispose(() => subscription.cancel()); // ⚠️ 自动清理
return subscription.stream;
}
// 在 Widget 中使用
Consumer(
builder: (context, ref, _) {
final ordersAsync = ref.watch(activeOrdersProvider);
return ordersAsync.when(
data: (orders) => OrderList(orders: orders),
loading: () => const CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
},
)
3.2 状态同步常见问题
dart
// ❌ 问题:在已销毁的 State 上调用 setState
class _MyState extends State<MyWidget> {
Future<void> _loadData() async {
final data = await fetchData();
setState(() => _data = data); // 如果此时 Widget 已销毁,会报错
}
}
// ✅ 解决:使用 mounted 检查
class _MyState extends State<MyWidget> {
Future<void> _loadData() async {
final data = await fetchData();
if (!mounted) return; // ⚠️ 检查是否还在 Widget 树中
setState(() => _data = data);
}
}
// ✅ 更优:使用 Riverpod(自动处理生命周期)
@riverpod
Future<Data> loadData(LoadDataRef ref) async {
// Riverpod 自动处理取消,无需 mounted 检查
return await fetchData();
}
四、生命周期与 Widget 绑定
4.1 WidgetsBindingObserver
监听应用级生命周期事件:
dart
class _HomePageState extends State<HomePage>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
// 应用回到前台:刷新数据、恢复播放
_refreshData();
break;
case AppLifecycleState.paused:
// 应用进入后台:保存草稿、暂停播放
_saveDraft();
break;
case AppLifecycleState.detached:
// 应用即将关闭
break;
case AppLifecycleState.inactive:
// 应用非活跃(来电、切换等)
break;
case AppLifecycleState.hidden:
// 应用不可见(Flutter 3.13+)
break;
}
}
@override
void didChangeLocales(List<Locale>? locales) {
// 系统语言变化
}
@override
void didChangePlatformBrightness() {
// 系统主题变化(深色/浅色)
}
}
小结
| 知识点 | 核心要点 |
|---|---|
| 控制器封装 | 将业务逻辑从 Widget 中分离,提高可测试性 |
| onInit / onClose | GetX 控制器生命周期,替代 initState/dispose |
| mounted 检查 | 异步操作后必须检查,防止 setState 报错 |
| Stream 订阅清理 | 在 dispose 中取消订阅,防止内存泄漏 |
| WidgetsBindingObserver | 监听应用前后台切换等系统事件 |
👉 下一章:四、路由与导航