Flutter Riverpod:AsyncNotifier 与 Notifier 详细分析对比
一、核心概述
1. Notifier
-
用途:同步状态管理
-
适用场景:简单状态,不需要异步操作
-
状态类型 :
T(任意同步类型)
2. AsyncNotifier
-
用途:异步状态管理
-
适用场景:需要异步加载、保存数据(如API调用、数据库操作)
-
状态类型 :
AsyncValue<T>(包装异步状态)
二、详细对比分析
类定义对比
dart
// Notifier - 同步
class CounterNotifier extends Notifier<int> {
@override
int build() {
return 0; // 直接返回同步值
}
}
// AsyncNotifier - 异步
class UserProfileNotifier extends AsyncNotifier<UserProfile> {
@override
FutureOr<UserProfile> build() async {
// 可以执行异步操作
return await _fetchUserProfile();
}
}
状态类型对比
| 特性 | Notifier | AsyncNotifier |
|---|---|---|
| 状态类型 | T |
AsyncValue<T> |
| 初始状态 | 直接值 | AsyncLoading |
| 错误处理 | 需手动处理 | 内置错误状态 |
| 加载状态 | 需手动管理 | 自动管理 |
AsyncValue 状态类型
dart
AsyncValue<T> 有三种状态:
1. AsyncLoading - 加载中
2. AsyncData(T data) - 数据加载成功
3. AsyncError(Object error, StackTrace stackTrace) - 加载失败
三、使用场景详解
适合使用 Notifier 的场景
dart
// 1. 计数器
class CounterNotifier extends Notifier<int> {
@override
int build() => 0;
void increment() => state++;
void decrement() => state--;
}
// 2. 简单的表单状态
class FormNotifier extends Notifier<FormData> {
@override
FormData build() => FormData.empty();
void updateField(String field, String value) {
state = state.copyWith(field: value);
}
}
适合使用 AsyncNotifier 的场景
dart
// 1. API数据获取
class ProductsNotifier extends AsyncNotifier<List<Product>> {
@override
Future<List<Product>> build() async {
return await _fetchProducts();
}
Future<void> refresh() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => _fetchProducts());
}
Future<void> addProduct(Product product) async {
final newProduct = await _api.addProduct(product);
state = AsyncValue.data([...state.value!, newProduct]);
}
}
// 2. 用户认证
class AuthNotifier extends AsyncNotifier<User?> {
@override
Future<User?> build() async {
return await _checkSavedToken();
}
Future<void> login(String email, String password) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => _performLogin(email, password));
}
}
四、方法对比
Notifier 核心方法
dart
abstract class Notifier<T> {
T build(); // 必须实现,返回初始状态
T get state; // 当前状态
set state(T value); // 设置新状态
void update((T state) => T cb); // 基于当前状态更新
}
AsyncNotifier 核心方法
dart
abstract class AsyncNotifier<T> {
FutureOr<T> build(); // 可以返回 Future
AsyncValue<T> get state;
set state(AsyncValue<T> value);
// 特有方法
Future<void> update((T? state) => FutureOr<T> cb);
Future<T> future; // 获取 build 返回的 Future
}
五、UI 中使用对比
Notifier 在 UI 中的使用
dart
final counterProvider = NotifierProvider<CounterNotifier, int>(
CounterNotifier.new,
);
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
},
)
AsyncNotifier 在 UI 中的使用
dart
final productsProvider = AsyncNotifierProvider<ProductsNotifier, List<Product>>(
ProductsNotifier.new,
);
Consumer(
builder: (context, ref, child) {
final productsAsync = ref.watch(productsProvider);
return productsAsync.when(
loading: () => CircularProgressIndicator(),
error: (error, stack) => ErrorWidget(error),
data: (products) => ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) => ProductItem(products[index]),
),
);
},
)
六、错误处理对比
Notifier 错误处理(需手动)
dart
class ManualErrorNotifier extends Notifier<Result<int>> {
@override
Result<int> build() => Result.success(0);
void riskyOperation() {
try {
final result = _doSomethingRisky();
state = Result.success(result);
} catch (e) {
state = Result.failure(e);
}
}
}
AsyncNotifier 错误处理(自动)
dart
class AutoErrorNotifier extends AsyncNotifier<int> {
@override
Future<int> build() async {
// 自动捕获异常并转为 AsyncError
return await _fetchData();
}
Future<void> retry() async {
// AsyncValue.guard 自动处理错误
state = await AsyncValue.guard(() => _fetchData());
}
}
七、性能与最佳实践
性能考虑
-
Notifier:更轻量,适合频繁更新的状态
-
AsyncNotifier:稍重,但提供了完整的异步状态管理
最佳实践
何时选择 Notifier
-
状态同步且简单
-
不需要加载/错误状态
-
状态更新频繁
-
本地状态管理
何时选择 AsyncNotifier
-
需要异步初始化
-
需要处理加载状态
-
需要内置错误处理
-
与API/数据库交互
-
复杂的数据流管理
混合使用示例
dart
// 使用 AsyncNotifier 处理数据获取,Notifier 处理 UI 状态
final userProvider = AsyncNotifierProvider<UserNotifier, User>(
UserNotifier.new,
);
final themeProvider = NotifierProvider<ThemeNotifier, ThemeData>(
ThemeNotifier.new,
);
// 在业务逻辑中结合使用
class UserDashboardNotifier extends Notifier<DashboardState> {
@override
DashboardState build() {
// 监听异步用户数据
final userAsync = ref.watch(userProvider);
final theme = ref.watch(themeProvider);
return userAsync.when(
loading: () => DashboardState.loading(theme),
error: (e, _) => DashboardState.error(e, theme),
data: (user) => DashboardState.success(user, theme),
);
}
}
八、迁移示例
从 Notifier 迁移到 AsyncNotifier
dart
// 之前:手动管理加载状态
class OldUserNotifier extends Notifier<UserState> {
@override
UserState build() => UserState.loading();
Future<void> loadUser() async {
state = UserState.loading();
try {
final user = await api.getUser();
state = UserState.success(user);
} catch (e) {
state = UserState.error(e);
}
}
}
// 之后:使用 AsyncNotifier
class NewUserNotifier extends AsyncNotifier<User> {
@override
Future<User> build() => api.getUser();
Future<void> refresh() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => api.getUser());
}
}
总结
| 维度 | Notifier | AsyncNotifier |
|---|---|---|
| 复杂度 | 简单 | 中等 |
| 异步支持 | 需手动处理 | 内置支持 |
| 状态管理 | 同步状态 | 异步状态包装 |
| 错误处理 | 手动 | 自动 |
| 加载状态 | 手动 | 自动 |
| 适用场景 | 简单同步状态 | 异步数据流 |
| 性能 | 更轻量 | 稍重但功能全 |
选择建议:
-
如果状态完全是同步的,不需要加载/错误状态 → 使用 Notifier
-
如果涉及异步操作(API、数据库等) → 使用 AsyncNotifier
-
对于复杂应用,通常需要混合使用两者