Flutter Riverpod 状态管理:构建可扩展的应用架构
掌握 Riverpod 的核心概念和最佳实践,构建更加可维护的 Flutter 应用。
一、Riverpod 简介
作为一名追求像素级还原的 UI 匠人,我对 Flutter 的状态管理方案有着深入的研究。Riverpod 是由 Flutter 社区知名开发者 Remi Rousselet 开发的状态管理库,它是 Provider 的继任者,提供了更强大、更灵活的状态管理解决方案。从简单的局部状态到复杂的全局状态,Riverpod 为我们提供了一套完整的状态管理工具。
二、核心概念
1. Provider
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 创建一个简单的 provider
final counterProvider = StateProvider((ref) => 0);
// 在组件中使用
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: Text('计数器')),
body: Center(
child: Text('计数: $count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Icon(Icons.add),
),
);
}
}
2. StateNotifierProvider
// 定义状态类
class Todo {
final String id;
final String title;
final bool completed;
Todo({required this.id, required this.title, this.completed = false});
Todo copyWith({String? id, String? title, bool? completed}) {
return Todo(
id: id ?? this.id,
title: title ?? this.title,
completed: completed ?? this.completed,
);
}
}
// 定义状态管理器
class TodoNotifier extends StateNotifier<List<Todo>> {
TodoNotifier() : super([]);
void addTodo(String title) {
final newTodo = Todo(
id: DateTime.now().toString(),
title: title,
);
state = [...state, newTodo];
}
void toggleTodo(String id) {
state = state.map((todo) {
if (todo.id == id) {
return todo.copyWith(completed: !todo.completed);
}
return todo;
}).toList();
}
void removeTodo(String id) {
state = state.where((todo) => todo.id != id).toList();
}
}
// 创建 provider
final todoProvider = StateNotifierProvider<TodoNotifier, List<Todo>>((ref) {
return TodoNotifier();
});
// 在组件中使用
class TodoListWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final todos = ref.watch(todoProvider);
return Scaffold(
appBar: AppBar(title: Text('待办事项')),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
return ListTile(
title: Text(
todo.title,
style: TextStyle(
decoration: todo.completed ? TextDecoration.lineThrough : null,
),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Checkbox(
value: todo.completed,
onChanged: (_) {
ref.read(todoProvider.notifier).toggleTodo(todo.id);
},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
ref.read(todoProvider.notifier).removeTodo(todo.id);
},
),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 显示添加待办事项的对话框
showDialog(
context: context,
builder: (context) {
final controller = TextEditingController();
return AlertDialog(
title: Text('添加待办事项'),
content: TextField(
controller: controller,
decoration: InputDecoration(hintText: '输入待办事项'),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('取消'),
),
TextButton(
onPressed: () {
if (controller.text.isNotEmpty) {
ref.read(todoProvider.notifier).addTodo(controller.text);
Navigator.pop(context);
}
},
child: Text('添加'),
),
],
);
},
);
},
child: Icon(Icons.add),
),
);
}
}
3. FutureProvider
// 创建 FutureProvider
final userProvider = FutureProvider<User>((ref) async {
final apiService = ref.watch(apiServiceProvider);
return await apiService.getUser();
});
// 定义数据模型
class User {
final String id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
// 定义 API 服务
class ApiService {
Future<User> getUser() async {
// 模拟网络请求
await Future.delayed(Duration(seconds: 2));
return User(
id: '1',
name: '张三',
email: '[email protected]',
);
}
}
final apiServiceProvider = Provider((ref) => ApiService());
// 在组件中使用
class UserWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsyncValue = ref.watch(userProvider);
return userAsyncValue.when(
data: (user) => Column(
children: [
Text('ID: ${user.id}'),
Text('姓名: ${user.name}'),
Text('邮箱: ${user.email}'),
],
),
loading: () => CircularProgressIndicator(),
error: (error, stackTrace) => Text('错误: $error'),
);
}
}
4. StreamProvider
// 创建 StreamProvider
final timerProvider = StreamProvider<int>((ref) {
return Stream.periodic(Duration(seconds: 1), (count) => count);
});
// 在组件中使用
class TimerWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final timerAsyncValue = ref.watch(timerProvider);
return timerAsyncValue.when(
data: (count) => Text('秒数: $count'),
loading: () => CircularProgressIndicator(),
error: (error, stackTrace) => Text('错误: $error'),
);
}
}
三、高级用法
1. 依赖注入
// 定义服务
class AuthService {
Future<bool> login(String email, String password) async {
// 模拟登录
await Future.delayed(Duration(seconds: 1));
return email == '[email protected]' && password == 'password';
}
void logout() {
// 执行登出操作
}
}
class ApiService {
final AuthService authService;
ApiService(this.authService);
Future<Map<String, dynamic>> fetchData() async {
// 模拟 API 请求
await Future.delayed(Duration(seconds: 1));
return {'data': 'Hello World'};
}
}
// 创建 providers
final authServiceProvider = Provider((ref) => AuthService());
final apiServiceProvider = Provider((ref) {
final authService = ref.watch(authServiceProvider);
return ApiService(authService);
});
// 在组件中使用
class HomeWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final apiService = ref.watch(apiServiceProvider);
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: ElevatedButton(
onPressed: () async {
final data = await apiService.fetchData();
print(data);
},
child: Text('获取数据'),
),
),
);
}
}
2. 状态组合
// 定义 providers
final counterProvider = StateProvider((ref) => 0);
final doubledCounterProvider = Provider((ref) {
final count = ref.watch(counterProvider);
return count * 2;
});
// 在组件中使用
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
final doubledCount = ref.watch(doubledCounterProvider);
return Scaffold(
appBar: AppBar(title: Text('计数器')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('计数: $count'),
Text('双倍计数: $doubledCount'),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Icon(Icons.add),
),
);
}
}
3. 作用域管理
// 创建一个作用域 provider
final userIdProvider = Provider<String>((ref) => throw UnimplementedError());
final userProvider = FutureProvider<User>((ref) async {
final userId = ref.watch(userIdProvider);
final apiService = ref.watch(apiServiceProvider);
return await apiService.getUserById(userId);
});
// 在组件中使用
class UserProfileWidget extends ConsumerWidget {
final String userId;
UserProfileWidget(this.userId);
@override
Widget build(BuildContext context, WidgetRef ref) {
return ProviderScope(
overrides: [
userIdProvider.overrideWithValue(userId),
],
child: UserProfileContent(),
);
}
}
class UserProfileContent extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsyncValue = ref.watch(userProvider);
return userAsyncValue.when(
data: (user) => Column(
children: [
Text('姓名: ${user.name}'),
Text('邮箱: ${user.email}'),
],
),
loading: () => CircularProgressIndicator(),
error: (error, stackTrace) => Text('错误: $error'),
);
}
}
四、实战案例
1. 完整的状态管理系统
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 定义数据模型
class Product {
final String id;
final String name;
final double price;
final String imageUrl;
Product({
required this.id,
required this.name,
required this.price,
required this.imageUrl,
});
}
// 定义购物车项
class CartItem {
final Product product;
final int quantity;
CartItem(this.product, this.quantity);
double get totalPrice => product.price * quantity;
}
// 定义状态管理器
class CartNotifier extends StateNotifier<List<CartItem>> {
CartNotifier() : super([]);
void addProduct(Product product) {
final existingIndex = state.indexWhere((item) => item.product.id == product.id);
if (existingIndex >= 0) {
// 产品已存在,增加数量
final updatedItems = [...state];
updatedItems[existingIndex] = CartItem(
product,
updatedItems[existingIndex].quantity + 1,
);
state = updatedItems;
} else {
// 新产品,添加到购物车
state = [...state, CartItem(product, 1)];
}
}
void removeProduct(String productId) {
state = state.where((item) => item.product.id != productId).toList();
}
void updateQuantity(String productId, int quantity) {
if (quantity <= 0) {
removeProduct(productId);
return;
}
state = state.map((item) {
if (item.product.id == productId) {
return CartItem(item.product, quantity);
}
return item;
}).toList();
}
double get totalAmount {
return state.fold(0, (sum, item) => sum + item.totalPrice);
}
}
// 创建 providers
final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) {
return CartNotifier();
});
final totalAmountProvider = Provider<double>((ref) {
final cart = ref.watch(cartProvider);
return cart.fold(0, (sum, item) => sum + item.totalPrice);
});
// 模拟产品数据
final products = [
Product(
id: '1',
name: 'iPhone 13',
price: 5999,
imageUrl: 'https://example.com/iphone13.jpg',
),
Product(
id: '2',
name: 'MacBook Pro',
price: 12999,
imageUrl: 'https://example.com/macbookpro.jpg',
),
Product(
id: '3',
name: 'iPad Pro',
price: 6999,
imageUrl: 'https://example.com/ipadpro.jpg',
),
];
// 产品列表组件
class ProductListWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: Text('产品列表'),
actions: [
Consumer(
builder: (context, ref, child) {
final cartItems = ref.watch(cartProvider);
return Stack(
children: [
IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CartWidget()),
);
},
),
if (cartItems.isNotEmpty)
Positioned(
top: 0,
right: 0,
child: Container(
padding: EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(10),
),
constraints: BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Text(
cartItems.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 10,
),
textAlign: TextAlign.center,
),
),
),
],
);
},
),
],
),
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
leading: Image.network(product.imageUrl, width: 50, height: 50),
title: Text(product.name),
subtitle: Text('¥${product.price}'),
trailing: ElevatedButton(
onPressed: () {
ref.read(cartProvider.notifier).addProduct(product);
},
child: Text('加入购物车'),
),
);
},
),
);
}
}
// 购物车组件
class CartWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final cartItems = ref.watch(cartProvider);
final totalAmount = ref.watch(totalAmountProvider);
if (cartItems.isEmpty) {
return Scaffold(
appBar: AppBar(title: Text('购物车')),
body: Center(child: Text('购物车为空')),
);
}
return Scaffold(
appBar: AppBar(title: Text('购物车')),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: cartItems.length,
itemBuilder: (context, index) {
final item = cartItems[index];
return ListTile(
leading: Image.network(item.product.imageUrl, width: 50, height: 50),
title: Text(item.product.name),
subtitle: Text('¥${item.product.price} x ${item.quantity} = ¥${item.totalPrice}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
ref.read(cartProvider.notifier).updateQuantity(
item.product.id,
item.quantity - 1,
);
},
),
Text(item.quantity.toString()),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
ref.read(cartProvider.notifier).updateQuantity(
item.product.id,
item.quantity + 1,
);
},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
ref.read(cartProvider.notifier).removeProduct(item.product.id);
},
),
],
),
);
},
),
),
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'总计:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
'¥$totalAmount',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.red),
),
],
),
),
ElevatedButton(
onPressed: () {
// 执行结算操作
print('结算金额: ¥$totalAmount');
},
child: Text('结算'),
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 50),
),
),
],
),
);
}
}
// 应用入口
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Riverpod 购物车示例',
home: ProductListWidget(),
);
}
}
五、最佳实践
- 模块化:将不同功能的状态管理分离到不同的 provider 中
- 单一职责:每个 provider 只负责管理一种类型的状态
- 依赖注入:使用 provider 进行依赖注入,提高代码的可测试性
- 状态组合:通过组合多个 provider 来构建复杂的状态逻辑
- 性能优化:使用 const 构造器和选择性监听来优化性能
- 错误处理:正确处理 FutureProvider 和 StreamProvider 中的错误
- 测试:为状态管理逻辑编写单元测试
六、常见问题
1. 状态更新不触发重建
// 确保使用 Consumer 或 ConsumerWidget
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('计数: $count');
},
);
2. 性能问题
// 使用 const 构造器
class MyWidget extends ConsumerWidget {
const MyWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// 只监听需要的状态
final count = ref.watch(counterProvider);
return Text('计数: $count');
}
}
3. 依赖循环
// 避免循环依赖
final providerA = Provider((ref) {
// 不要在这里监听 providerB
return SomeValue();
});
final providerB = Provider((ref) {
// 不要在这里监听 providerA
return AnotherValue();
});
七、与其他状态管理方案的比较
| 特性 | Riverpod | Provider | Bloc | Redux |
|---|---|---|---|---|
| 类型安全 | ✅ | ✅ | ✅ | ❌ |
| 依赖注入 | ✅ | ✅ | ❌ | ❌ |
| 异步支持 | ✅ | ✅ | ✅ | ❌ |
| 代码简洁 | ✅ | ❌ | ❌ | ❌ |
| 学习曲线 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
八、总结
Riverpod 是 Flutter 生态系统中强大的状态管理解决方案,它提供了类型安全、依赖注入、异步支持等特性,让我们能够构建更加可维护、可测试的应用。作为一名 UI 匠人,我推荐使用 Riverpod 来管理应用的状态,它能够帮助我们创建出更加优雅、高效的 Flutter 应用。
Riverpod 为 Flutter 状态管理带来了新的可能性,让状态管理变得更加简单、灵活和可扩展。
#flutter #riverpod #state-management #ui #dart
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/leopold_man/article/details/159954811



