Flutter 简单封装http网络框架
Flutter 实现下拉刷新和自动加载更多
Flutter Banner封装
Flutter使用官方CustomScrollView实现复杂页面下拉刷新和加载更多
Flutter之Router和Navigator实现页面跳转
Flutter的基本应用
引言
本文将全面介绍 Riverpod 的状态容器(Provider)与状态管理器(Notifier)的用法、组合使用以及状态定义策略以及模块化组织的最佳实践,助你构建可维护的大型 Flutter 应用。
一、核心哲学:理解状态管理的本质
状态管理的双支柱模型
在 Riverpod 中,状态管理建立在两个核心概念上:
-
状态容器 (Provider)
- 本质:数据的静态持有者
- 类比:图书馆的书架 - 存储书籍(数据)但不处理借阅流程
- 职责:安全存储和提供数据
- 特点:
- 数据不可变(immutable)
- 无业务逻辑
- 被动提供数据
-
状态管理器 (Notifier)
- 本质:数据的动态处理器
- 类比:图书管理员 - 管理书籍借阅、归还等流程
- 职责:处理数据变更和业务逻辑
- 特点:
- 封装业务规则
- 主动管理状态
- 处理状态转换
riverpod.png
为什么需要两者?
- 关注点分离:状态容器专注数据存储,状态管理器专注业务逻辑
- 可复用性:服务可在多个管理器间共享
- 可测试性:业务逻辑与数据源解耦
- 可维护性:变更数据源不影响业务逻辑
二、深度解析:状态容器详解
状态容器的核心特征
- 只读性:容器内数据创建后不可变
- 无状态性:不保存交互状态
- 服务导向:提供工具、服务或配置
状态容器的类型
1. Provider - 基础容器
// 提供日志服务
final loggerProvider = Provider<Logger>((ref) {
return Logger(
level: LogLevel.debug,
output: ConsoleOutput()
);
});
// 提供API客户端
final apiClientProvider = Provider<ApiClient>((ref) {
return ApiClient(
baseUrl: 'https://api.example.com',
timeout: Duration(seconds: 30)
);
});
2. FutureProvider - 异步数据容器
final userProfileProvider = FutureProvider<UserProfile>((ref) async {
final apiClient = ref.read(apiClientProvider);
return await apiClient.getUserProfile();
});
3. StreamProvider - 实时数据容器
final stockPriceProvider = StreamProvider<double>((ref) {
return StockTicker.getPriceStream('AAPL');
});
状态容器的生命周期
final tempDataProvider = Provider.autoDispose<String>((ref) {
// 当不再被监听时自动销毁
return 'Temporary data';
});
final persistentProvider = Provider<String>((ref) {
// 全局存在,直到应用关闭
return 'Persistent data';
});
三、深度解析:状态管理器详解
状态管理器的核心特征
- 业务逻辑封装:包含状态修改方法
- 状态可变性:通过创建新状态实例更新
- 主动管理:响应事件并处理状态转换
状态管理器的类型
1. NotifierProvider - 同步状态管理器
class ShoppingCartNotifier extends Notifier<List<CartItem>> {
@override
List<CartItem> build() => []; // 初始状态
void addItem(Product product) {
// 创建新状态实例(不可变原则)
state = [...state, CartItem(product: product)];
}
void removeItem(String productId) {
state = state.where((item) => item.product.id != productId).toList();
}
}
2. AsyncNotifierProvider - 异步状态管理器
class UserProfileNotifier extends AsyncNotifier<UserProfile> {
@override
Future<UserProfile> build() async {
// 异步初始化状态
return await _loadUserProfile();
}
Future<void> refreshProfile() async {
state = const AsyncValue.loading(); // 加载状态
try {
final profile = await _loadUserProfile();
state = AsyncValue.data(profile); // 成功状态
} catch (e, stack) {
state = AsyncValue.error(e, stack); // 错误状态
}
}
}
状态管理器的生命周期
class ChatNotifier extends Notifier<ChatState> {
@override
ChatState build() {
// 初始化时建立连接
final socket = WebSocket.connect('wss://chat.example.com');
ref.onDispose(() {
// 清理时关闭连接
socket.close();
});
return ChatState.initial();
}
// 消息处理方法...
}
四、状态容器与状态管理器的协作艺术
协作模式1:服务注入
// 状态容器:提供支付服务
final paymentServiceProvider = Provider<PaymentService>((ref) {
return PaymentService(
apiClient: ref.read(apiClientProvider),
logger: ref.read(loggerProvider)
);
});
// 状态管理器:使用支付服务
class CheckoutNotifier extends Notifier<CheckoutState> {
@override
CheckoutState build() => CheckoutState.initial();
Future<void> processPayment(PaymentDetails details) async {
final paymentService = ref.read(paymentServiceProvider);
try {
final result = await paymentService.process(details);
state = CheckoutState.completed(result);
} catch (e) {
state = CheckoutState.failed(e.toString());
}
}
}
协作模式2:状态转换
// 状态容器:提供原始产品数据
final productsProvider = FutureProvider<List<Product>>((ref) {
return ref.read(productServiceProvider).fetchAll();
});
// 状态管理器:转换并增强数据
class FeaturedProductsNotifier extends Notifier<List<FeaturedProduct>> {
@override
List<FeaturedProduct> build() {
final allProducts = ref.watch(productsProvider).value ?? [];
// 转换数据:筛选+增强
return allProducts
.where((product) => product.isFeatured)
.map((product) => FeaturedProduct(
product: product,
discount: _calculateDiscount(product),
))
.toList();
}
}
协作模式3:跨管理器通信
class OrderNotifier extends Notifier<OrderState> {
@override
OrderState build() => OrderState.initial();
Future<void> submitOrder() async {
// 从购物车管理器获取状态
final cartItems = ref.read(cartProvider);
// 从用户管理器获取状态
final user = ref.read(userProvider).user!;
// 创建订单
final order = Order(user: user, items: cartItems);
// 使用订单服务
final orderService = ref.read(orderServiceProvider);
await orderService.submit(order);
// 清空购物车
ref.read(cartProvider.notifier).clear();
// 更新订单状态
state = OrderState.completed(order);
}
}
五、状态设计的高级原则
1. 不可变性(Immutability)原则
// 错误:直接修改状态
state.items.add(newItem); // 违反不可变原则
// 正确:创建新状态实例
state = state.copyWith(
items: [...state.items, newItem],
total: state.total + newItem.price
);
2. 状态归一化(Normalization)
class AppState {
// 归一化数据存储
Map<String, Product> products;
Map<String, User> users;
// 关系映射
Map<String, List<String>> userOrders;
}
3. 状态派生(Derived State)
// 派生提供者:计算购物车总价
final cartTotalProvider = Provider<double>((ref) {
final cartItems = ref.watch(cartProvider);
return cartItems.fold(0, (total, item) => total + item.price);
});
// 派生提供者:筛选已完成订单
final completedOrdersProvider = Provider<List<Order>>((ref) {
final allOrders = ref.watch(ordersProvider);
return allOrders.where((order) => order.isCompleted).toList();
});
六、Riverpod Provider 类型决策树
riverpod1.png
七、实战:电商应用状态架构
分层架构实现
lib/
├── core/
│ ├── services/ # 服务实现
│ │ ├── product_service.dart
│ │ ├── cart_service.dart
│ │ └── payment_service.dart
│ │
│ ├── providers/ # 状态容器
│ │ ├── service_providers.dart
│ │ ├── api_providers.dart
│ │ └── config_providers.dart
│ │
│ └── models/ # 数据模型
│ ├── product.dart
│ ├── cart.dart
│ └── order.dart
│
├── features/
│ ├── product/
│ │ ├── notifiers/ # 产品状态管理器
│ │ │ └── product_notifier.dart
│ │ │
│ │ ├── providers/ # 产品状态容器
│ │ │ └── product_providers.dart
│ │ │
│ │ └── presentation/ # UI组件
│ │ ├── product_list.dart
│ │ └── product_detail.dart
│ │
│ ├── cart/
│ └── order/
│
└── app.dart # 应用入口
状态管理器实现
// features/cart/notifiers/cart_notifier.dart
class CartNotifier extends Notifier<CartState> {
@override
CartState build() => CartState.empty();
void addItem(Product product) {
// 使用日志服务(来自状态容器)
ref.read(loggerProvider).log('Adding ${product.name} to cart');
// 创建新状态实例
state = state.copyWith(
items: [...state.items, CartItem(product: product)],
total: state.total + product.price
);
}
Future<void> checkout() async {
// 使用支付服务(来自状态容器)
final paymentService = ref.read(paymentServiceProvider);
try {
state = state.copyWith(status: CartStatus.processing);
final result = await paymentService.processPayment(state);
state = state.copyWith(status: CartStatus.completed);
} catch (e) {
ref.read(loggerProvider).error('Checkout failed', e);
state = state.copyWith(status: CartStatus.failed, error: e.toString());
}
}
}
状态容器实现
// core/providers/service_providers.dart
final paymentServiceProvider = Provider<PaymentService>((ref) {
// 依赖其他状态容器
return PaymentService(
apiClient: ref.read(apiClientProvider),
config: ref.read(configProvider),
logger: ref.read(loggerProvider)
);
});
final loggerProvider = Provider<Logger>((ref) {
return Logger(
level: ref.watch(configProvider).logLevel,
output: FileOutput('app.log')
);
});
八、性能优化与最佳实践
1. 精细状态监听
// 错误:监听整个状态对象
final cartState = ref.watch(cartProvider);
// 正确:只监听需要的部分
final totalPrice = ref.watch(
cartProvider.select((state) => state.total)
);
final itemCount = ref.watch(
cartProvider.select((state) => state.items.length)
);
2. 自动资源释放
@riverpod
Future<Data> fetchData(FetchDataRef ref) async {
// 自动释放资源
final timer = Timer.periodic(Duration(seconds: 1), (t) {});
ref.onDispose(() => timer.cancel());
return await _loadData();
}
3. 状态更新批处理
void updateProfile(User user) {
// 避免多次重建
ref.read(userNotifierProvider.notifier).update((state) {
return state.copyWith(
name: user.name,
email: user.email,
avatar: user.avatar
);
});
}
4. 状态持久化
class AuthNotifier extends Notifier<AuthState> {
@override
AuthState build() {
// 从本地存储初始化状态
final storage = ref.read(localStorageProvider);
return storage.getAuthState() ?? AuthState.initial();
}
void login(User user) {
state = AuthState.authenticated(user);
// 持久化状态
ref.read(localStorageProvider).saveAuthState(state);
}
}
九、常见问题解决方案
问题1:循环依赖
// 解决方案:使用延迟访问
final serviceAProvider = Provider<ServiceA>((ref) {
return ServiceA(() => ref.read(serviceBProvider));
});
final serviceBProvider = Provider<ServiceB>((ref) {
return ServiceB(() => ref.read(serviceAProvider));
});
问题2:跨管理器通信
// 方案:状态监听
class AuthListener extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
ref.listen<AuthState>(authProvider, (_, state) {
if (state.user == null) {
ref.read(cartProvider.notifier).clear();
}
});
return SizedBox.shrink();
}
}
问题3:异步依赖初始化
final configProvider = FutureProvider<AppConfig>((ref) {
return loadConfig();
});
final apiClientProvider = Provider<ApiClient>((ref) {
final config = ref.watch(configProvider).value;
return ApiClient(config!.apiUrl);
});
class DataLoader extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final config = ref.watch(configProvider);
return config.when(
data: (_) => _buildContent(ref),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
}
}
十、总结:状态管理的艺术
状态容器 vs 状态管理器终极对比
维度 | 状态容器 (Provider) | 状态管理器 (Notifier) |
---|---|---|
核心职责 | 数据存储与提供 | 状态管理与业务逻辑执行 |
状态可变性 | 不可变 | 可变(通过新实例) |
业务逻辑 | 无 | 封装状态修改逻辑 |
更新机制 | 值变化时重建依赖 | 主动通知状态变化 |
典型用途 | 服务、配置、工具类 | 交互状态、业务流程 |
生命周期 | 通常全局存在 | 可配置局部或全局 |
测试重点 | 数据是否正确提供 | 业务逻辑是否正确执行 |
黄金实践原则
- 单一职责原则:每个Provider/Notifier只做一件事
- 不可变状态:总是创建新状态实例
- 依赖注入:管理器通过ref获取容器中的服务
- 精细监听:使用select只监听需要的状态部分
- 无论是状态管理者(Notifier)还是状态(state或数据) 都是需要和状态提供者(Provider)绑定方可达到状态共享
-
合理分层:
- UI层:展示数据
- 管理器层:处理业务逻辑
- 容器层:提供服务和数据
- 服务层:对接外部系统
何时使用什么?
-
简单配置/服务 →
Provider
-
简单交互状态 →
StateProvider
-
一次性数据加载 →
FutureProvider
-
实时数据流 →
StreamProvider
-
复杂交互逻辑 →
NotifierProvider
-
异步初始化状态 →
AsyncNotifierProvider
通过掌握状态容器和状态管理器的协作艺术,您可以构建出:
- 🚀 高性能:精确控制重建范围
- 🛠️ 可维护:清晰分离关注点
- 🔍 可测试:独立测试各组件
- 🌱 可扩展:轻松添加新功能
Riverpod 的状态管理体系犹如精心设计的瑞士手表,每个齿轮(Provider)都在正确的位置发挥精确的作用,共同构建出可靠高效的应用机制。