结合Riverpod的源码,详细解释工作实现原理

566 阅读2分钟

Riverpod 是一个 响应式的、基于依赖关系管理的 状态管理库,旨在解决 Provider 及其他状态管理方式中的一些问题,如:

  • 全局状态管理的安全性
  • 懒加载与自动销毁
  • BuildContext 依赖
  • 良好的组合性
  • 更强的类型安全
  • 异步支持

在解读源码之前,我们可以先了解一下 Riverpod 的核心理念

  1. Provider 只是一个工厂,它本身不会存储状态,状态的实际管理由 ProviderContainer 负责。
  2. Provider 之间的依赖关系由 Riverpod 维护,在 watch() 时自动追踪依赖,确保状态更新时能正确通知相关组件。
  3. 状态的创建和销毁是自动化的,不会导致内存泄漏。

1. Provider 的核心实现

1.1 ProviderBase:所有 Provider 的基类

ProviderStateProviderFutureProvider 等所有 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 检测 ConsumerWidgetConsumerStatefulWidget 何时销毁

2.2 Riverpod 监听 Widget 生命周期的关键代码

Riverpod 使用 ProviderSubscription 绑定 Provider 和 Widget,并监听 ElementLifecycle

dart
复制编辑
class ProviderSubscription<T> {
  final ProviderElement<T> element;

  void maybeDispose() {
    if (_listeners.isEmpty) {
      element.dispose(); // 触发销毁
    }
  }
}

工作原理

  1. ConsumerWidget 绑定 Provider

    • ProviderSubscription 负责追踪该 Provider 是否仍然被 Widget 使用。
    • ProviderSubscription 监听 ElementLifecycle,确保 Widget 销毁时,自动取消 watch() 订阅。
  2. 当 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()),它对 xxxProviderwatch() 也会断开。

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

对于 autoDisposeProvider

  • 只要 ProviderContainer 还存在,状态就不会被销毁,除非手动移除。

5.3 autoDispose Provider

对于 autoDisposeProvider

  • watch() 断开,且没有 keepAlive()

    • Riverpod 会在 ProviderContainer 的下一次 cleanup() 时销毁它
  • 没有组件监听该 Provider 时,Riverpod 自动销毁状态

**5.4 结合 keepAlive() 手动控制销毁

autoDispose 机制下,如果你希望某个 Providerwatch() 断开时不立即销毁,可以使用 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'),
);

总结

  1. Riverpod 使用 ProviderContainer 管理所有 Provider
  2. watch() 监听状态变化,read() 仅获取当前值
  3. 自动清理机制防止内存泄漏
  4. 依赖追踪自动更新相关 Provider
  5. 支持同步、异步、组合等多种状态管理方式

这就是 Riverpod 的底层实现原理,它提供了一种安全、灵活、高效的状态管理方案。