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

相关推荐
A懿轩A7 小时前
【2025版 OpenHarmony】GitCode 口袋工具 v1.0.3:Flutter + HarmonyOS 深色模式全面启用
flutter·harmonyos·openharmony·gitcode·开源鸿蒙
食品一少年7 小时前
【Day7-10】开源鸿蒙Flutter 常用组件封装实战(2)
flutter·华为·harmonyos
谢斯15 小时前
编译AppFlowy
flutter
灰灰勇闯IT18 小时前
Flutter×鸿蒙深度融合指南:从跨端适配到分布式能力落地(2025最新实战)
分布式·flutter·harmonyos
x.Jessica18 小时前
关于Flutter在Windows上开发的基本配置时遇到的问题及解决方法
windows·flutter
名字被你们想完了18 小时前
flutter 封装一个 tab
flutter
AiFlutter21 小时前
Flutter实现手电筒亮度修改
flutter
食品一少年1 天前
【Day7-10】开源鸿蒙之Flutter 的自定义组件封装(1)
flutter·开源·harmonyos
勇气要爆发1 天前
【第五阶段—高级特性和架构】第六章:自定义Widget开发指南
flutter
白茶三许1 天前
【2025】Flutter 卡片组件封装与分页功能实现:实战指南
flutter·开源·openharmony