用途
Provider 是 Riverpod 的核心特性:它们是带记忆(memoized)的函数,会缓存自己的结果,并允许多个 Widget(或其他 Provider)访问同一个值。Provider 以顶层 final 变量声明。状态存放在 ProviderContainer(Flutter 中为 ProviderScope)中,而不是存放在 Provider 本身。
Provider 变体
按返回类型分为三类:同步、Future、Stream。
- 不可修改(Unmodifiable):Provider、FutureProvider、StreamProvider
- 可修改(Modifiable):NotifierProvider、AsyncNotifierProvider、StreamNotifierProvider
选择规则:
- 同步 vs Future vs Stream:与函数的返回类型匹配(int、Future<T>、Stream<T>)。
- 不可修改:Widget 只读取值。用于计算或获取的数据。
- 可修改:暴露一个带 build() 方法和自定义方法的 Notifier;Widget 通过 ref.read(provider.notifier).someMethod() 调用。当 UI 需要更新状态时使用。
根据你想返回的内容选择类型,Provider 类型自然随之确定。FutureProvider / AsyncNotifierProvider 是最常用的。
创建 Provider(不可修改 / 函数式)
手动方式:
final userProvider = FutureProvider<User>((ref) async {
final response = await http.get('https://api.example.com/user/123');
return User.fromJson(response.body);
});
代码生成:用 @riverpod 注解一个顶层函数。第一个参数必须是 Ref ref。生成的 Provider 名称为 functionNameProvider。
@riverpod
Future<User> user(Ref ref) async {
final response = await http.get('https://api.example.com/user/123');
return User.fromJson(response.body);
}
修饰符:.autoDispose(或使用 @Riverpod(keepAlive: true) 来禁用),以及用于参数的 .family。参见 riverpod-auto-dispose 和 riverpod-family。
创建 Provider(可修改 / Notifier)
手动方式:使用 NotifierProvider(或 AsyncNotifierProvider / StreamNotifierProvider),配合一个继承 Notifier<T>、AsyncNotifier<T> 或 StreamNotifier<T> 的 Notifier 类。重写 build();不要把逻辑放在构造函数中(此时 ref/state 尚不可用)。公共方法通过 ref.read(provider.notifier).method() 调用。
final counterProvider = NotifierProvider<CounterNotifier, int>(CounterNotifier.new);
class CounterNotifier extends Notifier<int> {
@override
int build() => 0;
void increment() => state++;
}
代码生成:注解一个继承 _$ClassName 的类。重写 build();添加自定义方法。同样的规则:构造函数中不放逻辑。
@riverpod
class CounterNotifier extends _$CounterNotifier {
@override
int build() => 0;
void increment() => state++;
}
使用 Provider
- Flutter:用 ProviderScope 包裹应用。使用 Consumer、ConsumerWidget 或 ConsumerStatefulWidget 获取 ref,并调用 ref.watch(provider) 或 ref.read(provider)。
- 仅 Dart:创建 ProviderContainer(),然后 container.read(provider) 或 container.listen(...)。完成后调用 container.dispose()。
- 在另一个 Provider 内部:使用传给 Provider 函数的 Ref(或 Notifier 中的 this.ref)来 ref.watch / ref.read 其他 Provider。
Widget 中的示例:
return Consumer(
builder: (context, ref, _) {
final helloWorld = ref.watch(helloWorldProvider);
return Text(helloWorld);
},
);
你可以声明多个返回相同类型的 Provider;它们是相互独立的。关于 Ref、容器、修饰符和 Notifier 规则的更多细节,参见 reference.md。