当前位置: 首页 > news >正文

Riverpod原理解析(实现一个自己的Riverpod)

📚 Flutter 状态管理系列文章目录
  1. Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)

  2. setState() 使用详解:原理及注意事项

  3. InheritedWidget 组件使用及原理

  4. Flutter 中 Provider 的使用、注意事项与原理解析(含代码实战)

  5. GetX 用法详细解析以及注意事项

  6. Flutter BLoC 使用详细解析

  7. Flutter MobX 响应式原理与实战详解

  8. Flutter Riverpod 使用详细解析

  9. 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 会:

  1. 追踪这个 Provider 被哪些组件订阅;
  2. 如果状态变化了,只通知这些订阅者刷新;
  3. 它会懒加载 Provider,只在真正需要的时候创建;
  4. 在无人使用时自动释放内存。

🔁 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 框架,包含:

  1. ref.watch():支持依赖追踪与订阅更新
  2. autoDispose:无引用时自动释放
  3. 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 状态管理系列文章目录
  1. Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)

  2. setState() 使用详解:原理及注意事项

  3. InheritedWidget 组件使用及原理

  4. Flutter 中 Provider 的使用、注意事项与原理解析(含代码实战)

  5. GetX 用法详细解析以及注意事项

  6. Flutter BLoC 使用详细解析

  7. Flutter MobX 响应式原理与实战详解

  8. Flutter Riverpod 使用详细解析

  9. Riverpod原理解析(实现一个自己的Riverpod

相关文章:

  • 蜂鸟代理IP+云手机:跨境电商多账号运营的“隐形风控引擎”
  • 从提示工程(Prompt Engineering)到上下文工程(Context Engineering)
  • C++ 第三阶段:语言改进 - 第四节:nullptr vs NULL
  • Reactor Handle
  • MessagesPlaceholder和多轮AI翻译助手实战
  • ubuntu 远程桌面 xrdp + frp
  • 物奇微WQ5007A上手指南
  • opensbi从0到1入门学习
  • 基于dockerfile构建java springboot项目镜像
  • Java+Vue开发的SRM企业招采管理系统,一站式管理招采,助力企业高效运营
  • 系统分析师案例知识点
  • ​​Deepoc大模型在光电研发中的核心技术突破与应用​
  • 单例设计模式详解
  • vue3 定时刷新
  • PAT A 1052 Linked List Sorting
  • 【python实用小脚本-118】基于Flask的用户认证系统:app.py、forms.py与user.py解析
  • 夹子排名查看平台
  • 【江科大】Cursor 解析江科大倒立摆PID工程源码《00-PID综合测试程序-V1.1》《03-增量式PID定速控制》(Doxygen注释风格)
  • Webshell工具的流量特征分析(菜刀,蚁剑,冰蝎,哥斯拉)
  • python pyecharts 数据分析及可视化