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

相关推荐
奋斗的小青年!!1 小时前
OpenHarmony Flutter 拖拽排序组件性能优化与跨平台适配指南
flutter·harmonyos·鸿蒙
小雨下雨的雨2 小时前
Flutter 框架跨平台鸿蒙开发 —— Stack 控件之三维层叠艺术
flutter·华为·harmonyos
行者963 小时前
OpenHarmony平台Flutter手风琴菜单组件的跨平台适配实践
flutter·harmonyos·鸿蒙
小雨下雨的雨5 小时前
Flutter 框架跨平台鸿蒙开发 —— Flex 控件之响应式弹性布局
flutter·ui·华为·harmonyos·鸿蒙系统
cn_mengbei5 小时前
Flutter for OpenHarmony 实战:CheckboxListTile 复选框列表项详解
flutter
cn_mengbei5 小时前
Flutter for OpenHarmony 实战:Switch 开关按钮详解
flutter
奋斗的小青年!!5 小时前
OpenHarmony Flutter实战:打造高性能订单确认流程步骤条
flutter·harmonyos·鸿蒙
Coder_Boy_5 小时前
Flutter基础介绍-跨平台移动应用开发框架
spring boot·flutter
cn_mengbei5 小时前
Flutter for OpenHarmony 实战:Slider 滑块控件详解
flutter
行者965 小时前
Flutter跨平台骨架屏组件在鸿蒙系统上的实践与优化
flutter·harmonyos·鸿蒙