Riverpod原理解析(实现一个自己的Riverpod)
📚 Flutter 状态管理系列文章目录
-
Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)
-
setState() 使用详解:原理及注意事项
-
InheritedWidget 组件使用及原理
-
Flutter 中 Provider 的使用、注意事项与原理解析(含代码实战)
-
GetX 用法详细解析以及注意事项
-
Flutter BLoC 使用详细解析
-
Flutter MobX 响应式原理与实战详解
-
Flutter Riverpod 使用详细解析
-
Riverpod原理解析(实现一个自己的Riverpod
源码地址
🧠 为什么 Riverpod 可以“抽离状态逻辑”,不像 Provider 那样强依赖 widget tree?
✅ 原因:Riverpod 彻底摆脱了 Flutter 的 InheritedWidget
架构
Provider 的底层依赖的是 Flutter 的 widget 树(InheritedWidget
+ BuildContext
),所以它的状态:
- 必须嵌套在 widget 树中注册
- 读值/写值必须用 context(如 context.read)
而 Riverpod 的核心设计是“状态 = 纯 Dart 逻辑”,所以:
- 它不依赖 Widget tree,也不需要 BuildContext。
- 所有状态保存在一个叫做
ProviderContainer
的“容器”中。 - UI 组件只是读这个容器里的值,容器才是状态的大脑。
✨ 原理简述:Riverpod 是如何工作的?
核心组件包括:
名称 | 作用 |
---|---|
ProviderContainer | 所有状态 Provider 的注册、缓存、生命周期管理中心 |
Provider<T> | 一个状态提供者,返回类型为 T 的值 |
ref | 用来读取其它 Provider,追踪依赖关系 |
StateNotifier<T> | 一个可变状态的控制器 |
ConsumerWidget | 订阅 Provider 的 Flutter Widget |
当你 ref.watch(myProvider)
,Riverpod 会:
- 追踪这个 Provider 被哪些组件订阅;
- 如果状态变化了,只通知这些订阅者刷新;
- 它会懒加载 Provider,只在真正需要的时候创建;
- 在无人使用时自动释放内存。
🔁 Riverpod 工作流程图(概览)
+----------------+| Provider<T> | <---------++----------------+ || |ref.watch(provider) |v |+----------------+ || ref / Widget | || (记录依赖) | |+----------------+ || |v |+------------------+ || 构建 Provider 实例 | ------++------------------+|v+------------------+| 返回状态数据 |+------------------+|v+------------------+| ConsumerWidget || or HookWidget |+------------------+|状态更新时通知刷新
🧠 核心机制解释
步骤 | 说明 |
---|---|
1️⃣ Provider 定义 | 使用如 Provider , StateProvider , FutureProvider 定义一个状态数据入口。 |
2️⃣ ref.watch() | 在 Widget 中使用 ref.watch(provider) 订阅状态,Riverpod 会记录此依赖。 |
3️⃣ 创建 Provider 实例 | build() 方法会执行,并保存在 ProviderContainer 中(类似缓存)。 |
4️⃣ UI 渲染 | ConsumerWidget 会根据 provider 的值渲染 UI。 |
5️⃣ 状态变更通知 | 当状态更新,Riverpod 会通知所有 watch 了它的 Widget 自动刷新。 |
6️⃣ 自动销毁(可选) | 对于 autoDispose Provider,无依赖时自动释放,节省内存。 |
🧪 自己实现一个“迷你版 Riverpod”
我们来实现一个最简版的 Riverpod,只支持:
- 全局注册状态
- 订阅监听
- 改变状态时自动通知订阅者
好的!我们现在来一步步构建一个迷你版 Riverpod 框架,包含:
- ✅
ref.watch()
:支持依赖追踪与订阅更新 - ✅
autoDispose
:无引用时自动释放 - ✅
FutureProvider
:支持异步状态(加载中、成功、失败)
✅ 第一步:定义 Provider 接口和 Ref
类
abstract class BaseProvider<T> {T build(Ref ref);
}class Ref {final _listeners = <void Function()>[];void onChange(void Function() listener) {_listeners.add(listener);}void notify() {for (final listener in _listeners) {listener();}}
}
✅ 第二步:定义 Provider 容器和 ref.watch()
支持
class ProviderContainer {final Map<BaseProvider, dynamic> _cache = {};final Ref _ref = Ref();T watch<T>(BaseProvider<T> provider) {if (!_cache.containsKey(provider)) {_cache[provider] = provider.build(_ref);}return _cache[provider];}void refresh<T>(BaseProvider<T> provider) {_cache.remove(provider);_ref.notify(); // 通知所有依赖更新}
}
✅ 第三步:实现 StateProvider<T>
class StateProvider<T> extends BaseProvider<T> {T _value;StateProvider(this._value); T build(Ref ref) => _value;T get state => _value;set state(T newValue) {_value = newValue;}
}
✅ 第四步:实现 AutoDisposeProvider
class AutoDisposeProvider<T> extends BaseProvider<T> {final T Function(Ref ref) _creator;bool _isUsed = false;T? _cached;AutoDisposeProvider(this._creator); T build(Ref ref) {_isUsed = true;_cached ??= _creator(ref);return _cached!;}void maybeDispose() {if (!_isUsed) {_cached = null;} else {_isUsed = false;}}
}
✅ 第五步:实现 FutureProvider
class FutureProvider<T> extends BaseProvider<AsyncValue<T>> {final Future<T> Function(Ref ref) _future;FutureProvider(this._future); AsyncValue<T> build(Ref ref) {final asyncValue = AsyncValue<T>.loading();_future(ref).then((data) {asyncValue.setData(data);ref.notify(); // 通知刷新},onError: (err, stack) {asyncValue.setError(err);ref.notify();},);return asyncValue;}
}class AsyncValue<T> {T? _data;Object? _error;bool _loading = true;AsyncValue.loading();void setData(T data) {_data = data;_loading = false;}void setError(Object error) {_error = error;_loading = false;}bool get isLoading => _loading;bool get hasError => _error != null;T? get data => _data;Object? get error => _error;
}
✅ 使用示例(模拟 UI 层)
final counterProvider = StateProvider<int>(0);
final timeProvider = FutureProvider<String>((ref) async {await Future.delayed(Duration(seconds: 2));return DateTime.now().toIso8601String();
});void main() async {final container = ProviderContainer();// watch + 改变状态print('Counter: ${container.watch(counterProvider)}');counterProvider.state += 1;container.refresh(counterProvider); // 模拟更新print('Counter updated: ${container.watch(counterProvider)}');// watch FutureProviderfinal result = container.watch(timeProvider);print(result.isLoading ? 'Loading...' : result.data);await Future.delayed(Duration(seconds: 3));print(result.data ?? 'Failed');
}
我们现在继续为这个简易版 Riverpod 框架扩展以下高级功能:
✅ 功能目标
功能名称 | 描述 |
---|---|
✅ .listen() + UI绑定 | 支持类似 ConsumerWidget 的自动刷新 |
✅ 自动依赖跟踪 | 多个 Provider 依赖时自动刷新 |
✅ 缓存控制 + keepAlive() | 控制 Provider 是否被释放 |
✅ HookWidget /StatefulConsumer | 封装 UI,自动注册监听并响应刷新 |
🧱 1. .listen()
与 ConsumerWidget
我们实现一个类似 Flutter 的 UI 组件,只要 Provider 的值变化就刷新 build
。
✅ 改造 ProviderContainer:支持监听注册
class ProviderContainer {final Map<BaseProvider, dynamic> _cache = {};final Map<BaseProvider, List<VoidCallback>> _listeners = {};T watch<T>(BaseProvider<T> provider) {if (!_cache.containsKey(provider)) {_cache[provider] = provider.build(_ref);}// 自动追踪依赖_currentWatches.add(provider);return _cache[provider];}void listen<T>(BaseProvider<T> provider, VoidCallback listener) {_listeners.putIfAbsent(provider, () => []).add(listener);}void refresh<T>(BaseProvider<T> provider) {_cache.remove(provider);final newValue = provider.build(_ref);_cache[provider] = newValue;for (final l in _listeners[provider] ?? []) {l();}}final _ref = Ref();final Set<BaseProvider> _currentWatches = {};/// 收集构建中用到的所有 Providervoid beginBuild() => _currentWatches.clear();Set<BaseProvider> endBuild() => Set.from(_currentWatches);
}
🧠 2. 支持自动依赖跟踪
我们在 UI 层中:
abstract class ConsumerElement extends StatefulWidget {const ConsumerElement({super.key});Widget build(BuildContext context, WidgetRef ref); State<ConsumerElement> createState() => _ConsumerState();
}class _ConsumerState extends State<ConsumerElement> {late Set<BaseProvider> _watched;void initState() {super.initState();_setupListeners();}void _setupListeners() {container.beginBuild();widget.build(context, ref); // 触发一次依赖收集_watched = container.endBuild();for (var p in _watched) {container.listen(p, _triggerRebuild);}}void _triggerRebuild() {setState(() {});} Widget build(BuildContext context) {return widget.build(context, ref);}
}
💡 示例 UI 使用方式
class MyCounterWidget extends ConsumerElement { Widget build(BuildContext context, WidgetRef ref) {final count = container.watch(counterProvider);return Column(children: [Text("Count: $count"),ElevatedButton(onPressed: () {counterProvider.state++;container.refresh(counterProvider);},child: Text("Add"),)],);}
}
🔒 3. 添加 keepAlive
缓存控制
在 BaseProvider
加一个可选标志:
abstract class BaseProvider<T> {bool get keepAlive => false;T build(Ref ref);
}
对于 AutoDisposeProvider
等:
class MyAutoDisposeProvider<T> extends BaseProvider<T> {final T Function(Ref ref) _create;MyAutoDisposeProvider(this._create); T build(Ref ref) => _create(ref); bool get keepAlive => false; // 可通过构造控制
}
在 ProviderContainer
中,销毁逻辑为:
void cleanupUnusedProviders() {_cache.removeWhere((provider, _) => !provider.keepAlive);
}
可定时或页面退出时触发。
🧩 4. 简易 HookWidget / ConsumerStateful
如果你希望更灵活,我们可以提供一个简易 Hook:
class HookWidget extends StatefulWidget {final Widget Function(BuildContext, WidgetRef) builder;HookWidget(this.builder); State<HookWidget> createState() => _HookWidgetState();
}class _HookWidgetState extends State<HookWidget> { Widget build(BuildContext context) {container.beginBuild();final ui = widget.builder(context, ref);final deps = container.endBuild();for (final dep in deps) {container.listen(dep, () => setState(() {}));}return ui;}
}
使用方式:
HookWidget((context, ref) {final value = container.watch(counterProvider);return Text('$value');
})
✅ 总结:功能支持进展
功能 | 支持情况 |
---|---|
.listen() + ConsumerWidget | ✅ 已支持 |
自动依赖追踪(ref.watch) | ✅ 已实现 |
缓存控制、keepAlive | ✅ 已添加 |
简易 HookWidget / Stateful | ✅ 基础封装完成 |
源码地址
📚 Flutter 状态管理系列文章目录
-
Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)
-
setState() 使用详解:原理及注意事项
-
InheritedWidget 组件使用及原理
-
Flutter 中 Provider 的使用、注意事项与原理解析(含代码实战)
-
GetX 用法详细解析以及注意事项
-
Flutter BLoC 使用详细解析
-
Flutter MobX 响应式原理与实战详解
-
Flutter Riverpod 使用详细解析
-
Riverpod原理解析(实现一个自己的Riverpod