InheritedWidget是如何建立依赖关系的

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;
    }
  • _dependentsInheritedElement 中维护的依赖者列表(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

相关推荐
卢叁3 小时前
Flutter开发环境安装指南
前端·flutter
Levi14798654592894 小时前
flutter_flavorizr 多渠道打包、多环境打包利器,不需要再一个个手动配置了
flutter
LinXunFeng19 小时前
Flutter - 使用本地 DevTools 验证 SVG 加载优化
flutter·性能优化·svg
新镜21 小时前
Flutter 三棵树
flutter
上海大哥1 天前
Flutter 实现工程组件化(Windows电脑操作流程)
前端·flutter
风·之痕1 天前
Flutter Packge - 组件应用
flutter·packge
二哈喇子!2 天前
v-model双向绑定指令
flutter
吴Wu涛涛涛涛涛Tao2 天前
用 Flutter 实现一个「类 Instagram」Feed 列表页
flutter
叽哥2 天前
flutter学习第 8 节:路由与导航
android·flutter·ios