1.概述
ProviderScope可以理解成Provider的作用域,其内部会提供一个ProviderContainer负责维护ProviderElement。
- 对于全局的
provider,其状态会被保存在顶层ProviderScope里 - 对于通过
ProviderScope覆写(override)的provider,其状态会被保存在当前的作用域中 - 对于依赖了多个其他
Provider的provider,它会和自身依赖所处层级最深的provider对象处在相同的作用域中
collectionIdProvider就是一个被覆写的provider,它的状态会保存在当前ProviderScope中,而不是顶层。
ProviderScope和ProviderContainer整体较为简单,它们只负责管理ProviderElement,真正监听、刷新的逻辑都在ProviderElementBase里。
2. ProviderContainer
2.0 ProviderScope:向下提供ProviderContainer
ProviderScope是一个StatefulWidget。它会创建一个新的ProviderContainer、获取上级的ProviderContainer、并将它作为新Container的parent参数。
build方法会创建一个InheritedWidget:UncontrolledProviderScope,以向下传递ProviderContainer。
2.1 _StateReader:ProviderElement的容器
ProviderContainer不会直接保存ProviderElement,而是保存_StateReader对象。同时_StateReader也负责懒加载ProviderElement。
_StateReader中会保存
- 用作key的原始的
provider对象 - 实际生效的
override对象,是一个Provider ProviderElement所属的ProviderContainer对象- 是否是动态创建(或者说非override)的标记位
isDynamicallyCreated
class _StateReader {
_StateReader({
required this.origin,
required this.override,
required this.container,
// 是否为动态创建
required this.isDynamicallyCreated,
});
final ProviderBase<Object?> origin;
ProviderBase<Object?> override;
final ProviderContainer container;
final bool isDynamicallyCreated;
ProviderElementBase? _element;
// element是懒加载的
ProviderElementBase getElement() => _element ??= _create();
// 初始化ProviderElement的地方
ProviderElementBase _create() {
try {
final element = override.createElement()
.._provider = override
.._origin = origin
.._container = container
..mount();
return element;
} finally {}
}
}
2.2 ProviderContainer的创建过程
ProviderContainer是在ProviderScope中被创建的,ProviderScope又会把 上级parent、本级的overrides传递给所属的ProviderContainer。这里我们看看ProviderContainer是怎么处理这些参数的。
ProviderContainer({
ProviderContainer? parent,
List<Override> overrides = const [],
List<ProviderObserver>? observers,
}) : depth = parent == null ? 0 : parent.depth + 1,
_parent = parent,
// 借用parent中非动态创建的_stateReader
_stateReaders = {
if (parent != null)
for (final entry in parent._stateReaders.entries)
if (entry.value.isDynamicallyCreated == false) entry.key: entry.value,
},
_root = parent?._root ?? parent {
if (parent != null) {
parent._children.add(this);
_overrideForFamily.addAll(parent._overrideForFamily);
}
for (final override in overrides) {
if (override is ProviderOverride) {
// 保存被覆写的provider
_overrideForProvider[override._origin] = override._override;
// 提前创建被覆写的Provider所对应的_StateReader
_stateReaders[override._origin] = _StateReader(
origin: override._origin,
override: override._override,
container: this,
isDynamicallyCreated: false,
);
} else if (override is FamilyOverride) {
_overrideForFamily[override.overriddenFamily] = _FamilyOverrideRef(
override,
this,
);
}
}
}
根据这段代码,我们可以知道“作用域”的原理:
- 根据 自己 的
overrides参数,提前创建并保存对应的_StateReader。这些被提前创建的_StateReader又被称为“非动态创建”,isDynamicallyCreated == false。 - 借用 上级 非动态创建的
_StateReader。这里“借用”的意思是_StateReader仍属于创建它的ProviderContainer;它的container参数仍是上级而不是本级;当本ProviderContainer销毁时借来的_StateReader不受影响
3. 获取ProviderElement:_putIfAbsent()
之前我们提到ProviderElementBase被保存在_StateReader中。因此,获取ProviderElementBase首先就要获取其对应的_StateReader。考虑到ProviderScope可能存在嵌套关系,不同类型的Provider在_StateReader中的存储和获取方式会有所不同:
- 对于未覆写、无依赖的
Provider,其对应的ProviderElement应该存放在顶层ProviderContainer。 - 对于被覆写的
Provider,其Element应该在当前层。 - 对于没有被覆写但依赖了被覆写的
Provider,其Element应该存放在它所依赖被覆写的Provider的最深层级。
第3条看起来有点绕,举个例子就明白了。collectionInfo依赖于collectionId,而collectionId在ProviderScope中被覆写,此时collectionInfoProvider就是一个自身没有被覆写但依赖了被覆写的Provider的provider。collectionInfoProvider和collectionIdProvider所对应的ProviderElement在同一层。
_StateReader由ProviderContainer#_putIfAbsent创建,我会把步骤注释在代码中。
3.0 对于已保存的_StateReader
对于本级已经保存的对应的_StateReader,直接取出并返回,否则进入getReader()方法。
_StateReader _putIfAbsent(ProviderBase<Object?> provider) {
// 已保存在本层,直接返回
final currentReader = _stateReaders[provider];
if (currentReader != null) return currentReader;
_StateReader getReader() {
// 3.1 .....
// 3.2 .....
}
// 取出并缓存获取到的_StateReader,这样下一次就不用再跑麻烦的getReader方法了
return _stateReaders[provider] = getReader();
3.1 & 3.2 小节都是getReader()方法的一部分
3.1 对于 ProviderFamily
if (provider.from != null) {
// reading a family
final familyOverrideRef = _overrideForFamily[provider.from];
if (familyOverrideRef != null) {
// A family was overridden, so we implicitly mount the readers
if (familyOverrideRef.container._stateReaders.containsKey(provider)) {
return familyOverrideRef.container._stateReaders[provider]!;
}
void setupOverride({
required ProviderBase<Object?> origin,
required ProviderBase<Object?> override,
}) {
assert(
origin == override || override.dependencies == null,
'A provider override cannot specify `dependencies`',
);
// setupOverride may be called multiple times on different providers
// of the same family (provider vs provider.modifier), so we use ??=
// to initialize the providers only once
familyOverrideRef.container._stateReaders[origin] ??= _StateReader(
origin: origin,
override: override,
container: familyOverrideRef.container,
isDynamicallyCreated: true,
);
}
final providerOverride =
familyOverrideRef.override.getProviderOverride(provider);
setupOverride(origin: provider, override: providerOverride);
// if setupOverride overrode the provider, it was already initialized
// in the code above. Otherwise we initialize it as if it was not overridden
return familyOverrideRef.container._stateReaders[provider] ??
_StateReader(
origin: provider,
override: provider,
container: familyOverrideRef.container,
isDynamicallyCreated: true,
);
}
}
3.2 对于普通的 Provider
final root = _root;
if (root != null) {
// Provider可能依赖了其他的Provider,找出依赖
final dependencies = provider.from?.allTransitiveDependencies ??
provider.allTransitiveDependencies;
// 找到它们所在的ProviderContainer
final containerForDependencyOverride = dependencies
?.map((dep) {
final reader = _stateReaders[dep];
if (reader != null) {
return reader.container;
}
final familyOverride = _overrideForFamily[dep];
return familyOverride?.container;
})
.where((container) => container != null)
.toList();
// 如果有,找出层级最深的那个container
if (containerForDependencyOverride != null &&
containerForDependencyOverride.isNotEmpty) {
final deepestOverrideContainer = containerForDependencyOverride
.fold<ProviderContainer>(root, (previous, container) {
if (container!.depth > previous.depth) {
return container;
}
return previous;
});
// 新创建的ProviderElementBase应该存放到依赖层级最深的ProviderContainer中,放大作用域
return deepestOverrideContainer._stateReaders.putIfAbsent(provider,
() {
return _StateReader(
origin: provider,
override: provider,
container: deepestOverrideContainer,
isDynamicallyCreated: true,
);
});
}
} // end if (root != null)
// 到这里,如果这个provider显式依赖了其他的provider,那么它对应的_StateReader已经被创建并返回了
// 否则,这个provider没有依赖任何其他的provider。在根container中寻找
if (_root?._stateReaders.containsKey(provider) ?? false) {
return _root!._stateReaders[provider]!;
}
// 最顶层ProviderContainer中也没有这个provider对应的element。创建并将它放到最顶层中
final reader = _StateReader(
origin: provider,
// If a provider did not have an associated StateReader then it is
// guaranteed to not be overridden
override: provider,
// 当自己为根节点时,_root才为空
container: _root ?? this,
isDynamicallyCreated: true,
);
if (_root != null) {
_root!._stateReaders[provider] = reader;
}
return reader;
}
以上面举过的例子它为例,collectionId对应的_StateReader会属于图2的ProviderScope(而不是最顶层)中,而collectionInfo由于依赖了id,它对应的ProviderElement也在相同的ProviderContainer中。
图1里有一个appRepoProvider,它是全局的且不依赖其他provider,所以不管在哪里使用它,他都属于顶层ProviderContainer。
4. 读取read/监听watch/无效化invalidate
这其实是ProviderElement中的内容,但是它们都用到了ProviderContainer中的readProviderElement方法。这个方法通过_putIfAbsent找到当前层级的ProviderElement,后续操作交由Element完成。
@override
ProviderElementBase<State> readProviderElement<State>(ProviderBase<State> provider) {
final reader = _putIfAbsent(provider);
return reader.getElement() as ProviderElementBase<State>;
}
5. 释放当前ProviderContainer
获取所有属于本container的ProviderElement并释放它们。还记得开头提到“借用”的概念吗?被借用的_StateReader所有权仍属于它们原本的ProviderContainer,释放时会跳过他们。
void dispose() {
if (_disposed) return;
_disposed = true;
// 从上级ProviderContainer的孩子列表中移除自己
_parent?._children.remove(this);
// 如果是根节点,负责停止调度器
if (_root == null) scheduler.dispose();
// 释放属于自己的ProviderElement
for (final element in getAllProviderElementsInOrder().toList().reversed) {
element.dispose();
}
}
// 获取属于自己的ProviderElement
Iterable<ProviderElementBase> getAllProviderElements() sync* {
for (final reader in _stateReaders.values) {
// 跳过借用的_StateReader
if (reader._element != null && reader.container == this) {
yield reader._element!;
}
}
}
6. 调度器ProviderScheduler
和FlutterElement中的BuildOwner类似,ProviderContainer使用调度器来集中刷新ProviderElement。
6.1 内部变量
ProviderScheduler中维护了两个列表,分别记录了需要刷新和销毁的ProviderElement
// 需要销毁
final _stateToDispose = <AutoDisposeProviderElementMixin<Object?>>[];
// 需要刷新
final _stateToRefresh = <ProviderElementBase>[];
当某个ProviderElement需要被刷新时,就会通过
void scheduleProviderRefresh(ProviderElementBase element) {
_stateToRefresh.add(element);
_scheduleTask();
}
把自己加入到待刷新列表中,同时尝试调度一次任务。释放dispose同理。
注意:在_task执行时scheduleProviderRefresh也可能再次被调用。
6.2 任务_task、调度_scheduleTask和分帧vsync
6.2.1 任务_task
_task主要内容就是执行以下两个方法:按顺序刷新/销毁ProviderElement。
依次刷新。如果某个Provider没有监听者,跳过刷新。
void _performRefresh() {
for (var i = 0; i < _stateToRefresh.length; i++) {
final element = _stateToRefresh[i];
if (element.hasListeners) element.flush();
}
}
依次销毁。如果某个ProviderElement被保活/仍有监听者,跳过销毁。
void _performDispose() {
for (var i = 0; i < _stateToDispose.length; i++) {
final element = _stateToDispose[i];
final links = element._keepAliveLinks;
// 被保活/有监听者,跳过销毁
if (element.maintainState ||
(links != null && links.isNotEmpty) ||
element.hasListeners ||
element._container._disposed) {
continue;
}
element._container._disposeProvider(element._origin);
}
}
6.2.2 调度_scheduleTask
_pendingTaskCompleter可以理解成一个标记位,不为空表示已经有任务,跳过调度
void _scheduleTask() {
if (_pendingTaskCompleter != null || _disposed) return;
_pendingTaskCompleter = Completer<void>();
vsync(_task);
}
6.2.3 vsync
vsync是一个参数为方法的方法。执行时会把接受的方法包装到Future中,而Future会在下一帧开始(SchedulerPhase.idle)时调用。
void _defaultVsync(void Function() task) {
Future(task);
}
void Function(void Function()) get vsync {
return _defaultVsync;
}