Riverpod 是一个 响应式的、基于依赖关系管理的 状态管理库,旨在解决 Provider 及其他状态管理方式中的一些问题,如:
- 全局状态管理的安全性
- 懒加载与自动销毁
- 无
BuildContext依赖 - 良好的组合性
- 更强的类型安全
- 异步支持
在解读源码之前,我们可以先了解一下 Riverpod 的核心理念:
- Provider 只是一个工厂,它本身不会存储状态,状态的实际管理由
ProviderContainer负责。 - Provider 之间的依赖关系由 Riverpod 维护,在
watch()时自动追踪依赖,确保状态更新时能正确通知相关组件。 - 状态的创建和销毁是自动化的,不会导致内存泄漏。
1. Provider 的核心实现
1.1 ProviderBase:所有 Provider 的基类
Provider、StateProvider、FutureProvider 等所有 Provider 都继承自 ProviderBase,它是 Riverpod 状态管理的基石。
dart
复制编辑
abstract class ProviderBase<State> {
const ProviderBase();
State create(ProviderElement<State> ref);
}
-
这个基类定义了 Provider 的基本行为:
create()方法:用于生成State。- 具体的
Provider会通过create()定义自己的状态。
1.2 Provider(基础 Provider)
dart
复制编辑
class Provider<T> extends ProviderBase<T> {
Provider(this._create) : super();
final Create<T, ProviderRef<T>> _create;
@override
T create(ProviderElement<T> ref) {
return _create(ref);
}
}
_create是用户定义的回调函数,用于创建T类型的状态。create()只有在ProviderContainer请求该 Provider 的状态 时才会执行(懒加载)。
1.3 ProviderContainer(管理 Provider 的核心)
dart
复制编辑
class ProviderContainer {
final _providers = <ProviderBase, ProviderElement>{};
T read<T>(ProviderBase<T> provider) {
return _readElement(provider).state;
}
ProviderElement<T> _readElement<T>(ProviderBase<T> provider) {
return _providers.putIfAbsent(provider, () {
final element = provider.createElement();
element.mount();
return element;
}) as ProviderElement<T>;
}
}
-
_providers:存储所有Provider及其ProviderElement(持有状态)。 -
read():返回Provider的状态,不会监听状态变化。 -
_readElement():- 若
Provider还未创建,则调用createElement()创建ProviderElement。 - 调用
mount()使其进入运行状态(支持自动销毁)。
- 若
总结:
ProviderContainer维护 所有 Provider 的生命周期。ProviderContainer通过_providers缓存已创建的ProviderElement,避免重复创建。
2. 监听机制:watch vs read
2.1 watch
在 Riverpod 组件(如 ConsumerWidget)中,ref.watch() 用于监听 Provider 的状态。ref.watch() 会将 Provider 绑定到当前 Widget,并在 Widget 依赖更新时触发重建。
dart
复制编辑
class ConsumerWidget extends StatelessWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Counter: $count');
}
}
源码解析:
dart
复制编辑
T watch<T>(ProviderBase<T> provider) {
final element = _readElement(provider);
element.addListener(_markNeedsNotify);
return element.state;
}
-
watch()会在ProviderElement上注册监听器,当state变化时:- 组件会重新
build()以更新 UI。 ProviderElement触发notifyListeners()。
- 组件会重新
那么widget被移除时,如何检测到呢?
Riverpod 不会直接监听 Widget 的生命周期,而是通过 Flutter 框架的 ElementLifecycle 检测 ConsumerWidget 或 ConsumerStatefulWidget 何时销毁。
2.2 Riverpod 监听 Widget 生命周期的关键代码
Riverpod 使用 ProviderSubscription 绑定 Provider 和 Widget,并监听 ElementLifecycle:
dart
复制编辑
class ProviderSubscription<T> {
final ProviderElement<T> element;
void maybeDispose() {
if (_listeners.isEmpty) {
element.dispose(); // 触发销毁
}
}
}
工作原理
-
当
ConsumerWidget绑定Provider时:ProviderSubscription负责追踪该Provider是否仍然被Widget使用。ProviderSubscription监听ElementLifecycle,确保Widget销毁时,自动取消watch()订阅。
-
当 Widget 销毁(
dispose()触发)时:ProviderSubscription检测到ElementLifecycle变为unmounted。- 取消
watch()订阅,并调用maybeDispose()触发Provider状态销毁检查。
2.2 read
read() 用于获取 Provider 的值,但不会监听其变化。
dart
复制编辑
T read<T>(ProviderBase<T> provider) {
return _readElement(provider).state;
}
区别:
| 方法 | 作用 | 是否监听变化 |
|---|---|---|
watch() | 监听 Provider,UI 变化时重建 | ✅ |
read() | 仅获取当前值,不触发更新 | ❌ |
3. StateProvider(可变状态管理)
适用于: 存储简单的可变状态,如计数器。
dart
复制编辑
final counterProvider = StateProvider<int>((ref) => 0);
StateProvider返回StateController<T>,它封装了可变状态。
源码:
dart
复制编辑
class StateProvider<T> extends ProviderBase<StateController<T>> {
StateProvider(this._create) : super();
final Create<T, StateProviderRef<T>> _create;
@override
StateController<T> create(ProviderElement<StateController<T>> ref) {
return StateController(_create(ref));
}
}
class StateController<T> {
StateController(this._state);
T _state;
final _listeners = <void Function(T)>[];
T get state => _state;
set state(T newState) {
if (_state == newState) return;
_state = newState;
for (final listener in _listeners) {
listener(_state);
}
}
}
-
StateProvider包装了StateController<T>,它:- 维护
_state(实际存储的值)。 - 当
state变化时,通知所有监听者。
- 维护
4. 依赖管理
Riverpod 会自动追踪 Provider 之间的依赖,如:
dart
复制编辑
final providerA = Provider<int>((ref) => 10);
final providerB = Provider<int>((ref) => ref.watch(providerA) * 2);
providerB依赖providerA。- 当
providerA变化时,providerB也会自动更新。
内部实现(简化版):
dart
复制编辑
class ProviderElement<T> {
final _listeners = <void Function(T)>[];
void addListener(void Function(T) listener) {
_listeners.add(listener);
}
void notifyListeners() {
for (final listener in _listeners) {
listener(state);
}
}
}
5. 自动清理机制
Riverpod 自动回收未使用的 Provider,防止内存泄漏。也就是说,当没有地方再使用某个 Provider 时,Riverpod 会自动销毁该 Provider 的状态,释放内存。例如:当 XXXWidget 被移除时(例如 Navigator.pop()),它对 xxxProvider 的 watch() 也会断开。
5.1 AutoDisposeProvider
如果 Provider 被声明为 autoDispose,Riverpod 会在该 Provider 的引用不再被使用时自动清理状态:
dart
复制编辑
final myProvider = Provider.autoDispose<int>((ref) => 42);
autoDispose 关键在于 AutoDisposeProviderElementMixin,它会在 Provider 失去所有监听者时,延迟一段时间后自动销毁:
dart
复制编辑
mixin AutoDisposeProviderElementMixin<T> on ProviderElement<T> {
void maybeDispose() {
if (_listeners.isEmpty) {
_dispose();
}
}
void _dispose() {
state.dispose();
}
}
- 监听者为空时,调用
_dispose()释放状态。
5.2 非 autoDispose Provider
对于 非 autoDispose 的 Provider:
- 只要
ProviderContainer还存在,状态就不会被销毁,除非手动移除。
5.3 autoDispose Provider
对于 autoDispose 的 Provider:
-
当
watch()断开,且没有keepAlive():- Riverpod 会在
ProviderContainer的下一次cleanup()时销毁它。
- Riverpod 会在
-
当 没有组件监听该 Provider 时,Riverpod 自动销毁状态。
**5.4 结合 keepAlive() 手动控制销毁
在 autoDispose 机制下,如果你希望某个 Provider 在 watch() 断开时不立即销毁,可以使用 keepAlive():
dart
复制编辑
final myProvider = StateProvider.autoDispose<int>((ref) {
ref.keepAlive(); // 阻止自动销毁
return 0;
});
-
当
keepAlive()被调用:Provider不会立即销毁,即使watch()断开。- 但如果
ProviderContainer被销毁,这个Provider仍然会被释放。
6. FutureProvider & StreamProvider
Riverpod 还支持异步数据流,如:
dart
复制编辑
final futureProvider = FutureProvider<String>((ref) async {
await Future.delayed(Duration(seconds: 2));
return 'Data Loaded';
});
底层维护 AsyncValue<T> 类型:
dart
复制编辑
class AsyncValue<T> {
final T? value;
final bool isLoading;
final Object? error;
}
这样,UI 组件可以直接处理:
dart
复制编辑
final asyncValue = ref.watch(futureProvider);
asyncValue.when(
data: (data) => Text(data),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
总结
- Riverpod 使用
ProviderContainer管理所有 Provider。 - watch() 监听状态变化,read() 仅获取当前值。
- 自动清理机制防止内存泄漏。
- 依赖追踪自动更新相关 Provider。
- 支持同步、异步、组合等多种状态管理方式。
这就是 Riverpod 的底层实现原理,它提供了一种安全、灵活、高效的状态管理方案。