Flutter Riverpod 高级技巧优雅的状态管理掌握 Flutter Riverpod 状态管理的高级技巧创建优雅、可维护的应用。一、Riverpod 概述作为一名把代码当散文写的 UI 匠人我对 Flutter Riverpod 状态管理有着独特的见解。Riverpod 是 Provider 的进化版它提供了一种更灵活、更强大的状态管理方式。从简单的状态共享到复杂的异步数据处理Riverpod 为我们提供了一套全新的状态管理工具。就像指挥家手里的指挥棒一样Riverpod 让状态管理变得优雅而有序。二、基础 Provider1. Provider 基础import package:flutter/material.dart; import package:flutter_riverpod/flutter_riverpod.dart; // 基础 Provider final counterProvider Providerint((ref) 0); // StateProvider final counterStateProvider StateProviderint((ref) 0); // 使用 Provider class CounterWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final counter ref.watch(counterStateProvider); return Scaffold( appBar: AppBar(title: Text(计数器)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(当前计数: $counter, style: TextStyle(fontSize: 24)), SizedBox(height: 20), ElevatedButton( onPressed: () { ref.read(counterStateProvider.notifier).state; }, child: Text(增加), ), ], ), ), ); } }2. StateNotifierProvider// StateNotifier class CounterNotifier extends StateNotifierint { CounterNotifier() : super(0); void increment() state; void decrement() state--; void reset() state 0; } // StateNotifierProvider final counterNotifierProvider StateNotifierProviderCounterNotifier, int((ref) { return CounterNotifier(); }); // 使用 StateNotifierProvider class CounterNotifierWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final counter ref.watch(counterNotifierProvider); final notifier ref.read(counterNotifierProvider.notifier); return Scaffold( appBar: AppBar(title: Text(计数器)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(当前计数: $counter, style: TextStyle(fontSize: 24)), SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () notifier.decrement(), child: Text(-), ), SizedBox(width: 20), ElevatedButton( onPressed: () notifier.increment(), child: Text(), ), ], ), SizedBox(height: 20), TextButton( onPressed: () notifier.reset(), child: Text(重置), ), ], ), ), ); } }3. FutureProvider// FutureProvider final fetchUserProvider FutureProviderUser((ref) async { final response await http.get(Uri.parse(https://jsonplaceholder.typicode.com/users/1)); if (response.statusCode 200) { return User.fromJson(json.decode(response.body)); } else { throw Exception(Failed to load user); } }); // User 模型 class User { final int id; final String name; final String email; User({required this.id, required this.name, required this.email}); factory User.fromJson(MapString, dynamic json) { return User( id: json[id], name: json[name], email: json[email], ); } } // 使用 FutureProvider class UserWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final userAsync ref.watch(fetchUserProvider); return Scaffold( appBar: AppBar(title: Text(用户信息)), body: userAsync.when( loading: () Center(child: CircularProgressIndicator()), error: (error, stackTrace) Center(child: Text(错误: $error)), data: (user) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(ID: ${user.id}, style: TextStyle(fontSize: 18)), SizedBox(height: 10), Text(姓名: ${user.name}, style: TextStyle(fontSize: 18)), SizedBox(height: 10), Text(邮箱: ${user.email}, style: TextStyle(fontSize: 18)), ], ), ); }, ), ); } }4. StreamProvider// StreamProvider final streamCounterProvider StreamProviderint((ref) { return Stream.periodic(Duration(seconds: 1), (i) i).take(10); }); // 使用 StreamProvider class StreamCounterWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final streamAsync ref.watch(streamCounterProvider); return Scaffold( appBar: AppBar(title: Text(流计数器)), body: streamAsync.when( loading: () Center(child: CircularProgressIndicator()), error: (error, stackTrace) Center(child: Text(错误: $error)), data: (count) { return Center( child: Text( 当前计数: $count, style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold), ), ); }, ), ); } }三、高级 Provider1. 组合 Provider// 多个 Provider 组合 final firstNameProvider ProviderString((ref) 张); final lastNameProvider ProviderString((ref) 三); // 依赖其他 Provider final fullNameProvider ProviderString((ref) { final firstName ref.watch(firstNameProvider); final lastName ref.watch(lastNameProvider); return $firstName$lastName; }); // 使用组合 Provider class FullNameWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final fullName ref.watch(fullNameProvider); return Scaffold( appBar: AppBar(title: Text(姓名)), body: Center( child: Text( 全名: $fullName, style: TextStyle(fontSize: 24), ), ), ); } }2. AsyncNotifierProvider// AsyncNotifier class UserNotifier extends AsyncNotifierUser? { override FutureUser? build() async { return await _fetchUser(); } FutureUser? _fetchUser() async { final response await http.get(Uri.parse(https://jsonplaceholder.typicode.com/users/1)); if (response.statusCode 200) { return User.fromJson(json.decode(response.body)); } else { return null; } } Futurevoid refreshUser() async { state AsyncLoading(); state await AsyncValue.guard(() _fetchUser()); } } // AsyncNotifierProvider final userNotifierProvider AsyncNotifierProviderUserNotifier, User?(() { return UserNotifier(); }); // 使用 AsyncNotifierProvider class UserNotifierWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final userAsync ref.watch(userNotifierProvider); return Scaffold( appBar: AppBar( title: Text(用户信息), actions: [ IconButton( icon: Icon(Icons.refresh), onPressed: () { ref.read(userNotifierProvider.notifier).refreshUser(); }, ), ], ), body: userAsync.when( loading: () Center(child: CircularProgressIndicator()), error: (error, stackTrace) Center(child: Text(错误: $error)), data: (user) { if (user null) { return Center(child: Text(用户不存在)); } return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(ID: ${user.id}, style: TextStyle(fontSize: 18)), SizedBox(height: 10), Text(姓名: ${user.name}, style: TextStyle(fontSize: 18)), SizedBox(height: 10), Text(邮箱: ${user.email}, style: TextStyle(fontSize: 18)), ], ), ); }, ), ); } }3. Provider 修饰符// autoDispose final autoDisposeProvider Provider.autoDisposeString((ref) { return 这个 Provider 会在不再使用时自动销毁; }); // family final familyProvider Provider.familyString, int((ref, id) { return ID 为 $id 的数据; }); // 使用 family class FamilyWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final data1 ref.watch(familyProvider(1)); final data2 ref.watch(familyProvider(2)); return Scaffold( appBar: AppBar(title: Text(Family Provider)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(data1, style: TextStyle(fontSize: 18)), SizedBox(height: 20), Text(data2, style: TextStyle(fontSize: 18)), ], ), ), ); } } // keepAlive final keepAliveProvider ProviderString((ref) { ref.keepAlive(); return 这个 Provider 会保持存活; });四、实战案例1. 购物车// 购物车商品模型 class CartItem { final int id; final String name; final double price; int quantity; CartItem({ required this.id, required this.name, required this.price, this.quantity 1, }); } // 购物车 Notifier class CartNotifier extends NotifierListCartItem { override ListCartItem build() { return []; } void addItem(CartItem item) { final index state.indexWhere((i) i.id item.id); if (index ! -1) { state[index].quantity; state List.from(state); } else { state [...state, item]; } } void removeItem(int id) { state state.where((item) item.id ! id).toList(); } void updateQuantity(int id, int quantity) { final index state.indexWhere((i) i.id id); if (index ! -1) { state[index].quantity quantity; state List.from(state); } } double get total { return state.fold(0, (sum, item) sum item.price * item.quantity); } } // 购物车 Provider final cartProvider NotifierProviderCartNotifier, ListCartItem(() { return CartNotifier(); }); // 购物车页面 class CartPage extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final cart ref.watch(cartProvider); final cartNotifier ref.read(cartProvider.notifier); return Scaffold( appBar: AppBar(title: Text(购物车)), body: cart.isEmpty ? Center(child: Text(购物车为空, style: TextStyle(fontSize: 18))) : Column( children: [ Expanded( child: ListView.builder( itemCount: cart.length, itemBuilder: (context, index) { final item cart[index]; return ListTile( title: Text(item.name), subtitle: Text(单价: ¥${item.price.toStringAsFixed(2)}), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.remove), onPressed: () { if (item.quantity 1) { cartNotifier.updateQuantity(item.id, item.quantity - 1); } else { cartNotifier.removeItem(item.id); } }, ), Text(${item.quantity}), IconButton( icon: Icon(Icons.add), onPressed: () { cartNotifier.updateQuantity(item.id, item.quantity 1); }, ), IconButton( icon: Icon(Icons.delete), onPressed: () { cartNotifier.removeItem(item.id); }, ), ], ), ); }, ), ), Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: Offset(0, -2), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 总计: ¥${cartNotifier.total.toStringAsFixed(2)}, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ElevatedButton( onPressed: () { // 结算 }, child: Text(结算), ), ], ), ), ], ), ); } }2. 主题切换// 主题状态 enum AppTheme { light, dark, system } // 主题 Notifier class ThemeNotifier extends NotifierAppTheme { override AppTheme build() { return AppTheme.system; } void setTheme(AppTheme theme) { state theme; } } // 主题 Provider final themeProvider NotifierProviderThemeNotifier, AppTheme(() { return ThemeNotifier(); }); // 主题数据 Provider final themeDataProvider ProviderThemeData((ref) { final theme ref.watch(themeProvider); switch (theme) { case AppTheme.light: return ThemeData.light(); case AppTheme.dark: return ThemeData.dark(); case AppTheme.system: return WidgetsBinding.instance.platformDispatcher.platformBrightness Brightness.dark ? ThemeData.dark() : ThemeData.light(); } }); // 主题设置页面 class ThemeSettingsPage extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final currentTheme ref.watch(themeProvider); final themeNotifier ref.read(themeProvider.notifier); return Scaffold( appBar: AppBar(title: Text(主题设置)), body: ListView( children: [ RadioListTileAppTheme( title: Text(浅色主题), value: AppTheme.light, groupValue: currentTheme, onChanged: (value) { if (value ! null) { themeNotifier.setTheme(value); } }, ), RadioListTileAppTheme( title: Text(深色主题), value: AppTheme.dark, groupValue: currentTheme, onChanged: (value) { if (value ! null) { themeNotifier.setTheme(value); } }, ), RadioListTileAppTheme( title: Text(跟随系统), value: AppTheme.system, groupValue: currentTheme, onChanged: (value) { if (value ! null) { themeNotifier.setTheme(value); } }, ), ], ), ); } } // 主应用 class MyApp extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { final theme ref.watch(themeDataProvider); return MaterialApp( title: Riverpod 示例, theme: theme, home: HomePage(), ); } }五、最佳实践合理选择 Provider 类型根据需求选择合适的 Provider保持 Provider 简洁避免在 Provider 中做太多事情使用 family创建参数化的 Provider使用 autoDispose避免内存泄漏组合 Provider使用组合的方式创建复杂的状态逻辑测试 Provider为 Provider 编写测试六、性能优化使用 select只监听需要的部分避免过度重建使用 select 和 family 来限制重建合理使用 keepAlive只在必要时使用测试性能在不同设备上测试性能// 使用 select class SelectWidget extends ConsumerWidget { override Widget build(BuildContext context, WidgetRef ref) { // 只监听 counter 的值 final counter ref.select(counterProvider, (state) state); return Text(Counter: $counter); } }七、总结Flutter Riverpod 是一种优雅、强大的状态管理方案它可以让我们创建更加可维护、可测试的应用。通过掌握 Riverpod 的高级技巧我们可以创建出优雅、高效的状态管理逻辑。作为一名 UI 匠人我建议在项目中合理使用 Riverpod让状态管理变得优雅而有序。Riverpod 让状态管理变得优雅就像指挥家指挥交响乐一样有序。#flutter #riverpod #state-management #frontend #dart