InheritedWidget
建立依赖关系的过程,是通过 Flutter 的 Element
系统来完成的。
当我们在 build()
方法中使用 BuildContext.dependOnInheritedWidgetOfExactType<T>()
或其封装(比如 MyInheritedWidget.of(context)
)时,Flutter 框架就会将当前 Widget 所在的 Element 标记为依赖于某个 InheritedWidget
,以便它将来数据变化时能触发重建。
下面我会完整解释这个依赖关系是如何一步步建立的,包括源码逻辑。
✅ 1. 建立依赖关系的调用链
以你写的代码中最常用的:
dart
final model = MyInheritedWidget.of(context);
如果它内部调用的是:
dart
context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
那么整个调用链大致如下:
dart
dependOnInheritedWidgetOfExactType<T>()
└── getElementForInheritedWidgetOfExactType<T>()
└── _inheritedWidgets[T] => 找到最近的 InheritedElement
└── dependOnInheritedElement()
├── _dependencies.add(ancestor)
└── ancestor.updateDependencies(this, aspect) => 注册依赖
✅ 2. 实际建立依赖的核心代码
来自 Element
类的源码:
dart
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
// 当前 Element 添加对 InheritedElement 的依赖
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
// InheritedElement 注册这个依赖
ancestor.updateDependencies(this, aspect);
return ancestor.widget as InheritedWidget;
}
@override
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor = _inheritedElements == null ? null : _inheritedElements![T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
这里的"当前 Element"是正在 build 的 Widget 所对应的 Element。
🔗 _inheritedElements
是如何被记录的
dart
@override
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
final PersistentHashMap<Type, InheritedElement> incomingWidgets =
_parent?._inheritedElements ?? const PersistentHashMap<Type, InheritedElement>.empty();
_inheritedElements = incomingWidgets.put(widget.runtimeType, this);
}
@mustCallSuper
void mount(Element? parent, Object? newSlot) {
...
// 关联记录继承关系
_updateInheritance();
}
🔗 updateDependencies()
的作用
dart
void updateDependencies(Element dependent, Object? aspect) {
// 将这个 Element 添加到依赖列表中
_dependents[dependent] = aspect;
}
_dependents
是InheritedElement
中维护的依赖者列表(Map)- 这个列表记录了所有依赖它的 Widget 对应的 Element
- 当 InheritedWidget 变化时,遍历这些
_dependents
,触发它们的didChangeDependencies()
,从而触发重建
✅ 3. 如何触发依赖重建?
如果某个 InheritedWidget
重建了,框架会调用其 Element 的 update()
:
dart
@override
void update(InheritedWidget newWidget) {
final oldWidget = widget;
super.update(newWidget);
if (newWidget.updateShouldNotify(oldWidget)) {
notifyClients(oldWidget);
}
}
🔔 notifyClients(oldWidget)
的作用:
dart
@override
void notifyClients(InheritedWidget oldWidget) {
for (final Element dependent in _dependents.keys) {
notifyDependent(oldWidget, dependent);
}
}
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
dependent.didChangeDependencies();
}
每个依赖它的 Element 被告知 "你依赖的东西变了",触发重建
✅ 4. 重建是怎么发生的?
当依赖的 Element
收到通知后:
scss
@override
void didChangeDependencies() {
markNeedsBuild(); // 标记为需要重新构建
}
📌 总结:建立依赖的全过程
步骤 | 说明 |
---|---|
1. Widget 调用 context.dependOnInheritedWidgetOfExactType<T>() |
触发依赖建立 |
2. 获取最近的 InheritedElement<T> |
找到要依赖的对象 |
3. dependOnInheritedElement() |
当前 Widget 的 Element 注册依赖 |
4. InheritedElement.updateDependencis() |
记录依赖者(添加到 _dependents ) |
5. 当数据变化:InheritedWidget 重新 build,判断 updateShouldNotify |
判断是否通知下游 |
6. 如果通知:notifyClients() 遍历所有依赖者 |
每个依赖者的 didChangeDependencies() 被调用 |
7. Element 被标记 markNeedsBuild() |
重建 Widget |