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

相关推荐
一只大侠的侠几秒前
Flutter开源鸿蒙跨平台训练营 Day14React Native表单开发
flutter·开源·harmonyos
子春一8 分钟前
Flutter for OpenHarmony:音律尺 - 基于Flutter的Web友好型节拍器开发与节奏可视化实现
前端·flutter
微祎_36 分钟前
Flutter for OpenHarmony:单词迷宫一款基于 Flutter 构建的手势驱动字母拼词游戏,通过滑动手指连接字母路径来组成单词。
flutter·游戏
ujainu1 小时前
护眼又美观:Flutter + OpenHarmony 鸿蒙记事本一键切换夜间模式(四)
android·flutter·harmonyos
ujainu1 小时前
让笔记触手可及:为 Flutter + OpenHarmony 鸿蒙记事本添加实时搜索(二)
笔记·flutter·openharmony
一只大侠的侠1 小时前
Flutter开源鸿蒙跨平台训练营 Day 13从零开发注册页面
flutter·华为·harmonyos
一只大侠的侠1 小时前
Flutter开源鸿蒙跨平台训练营 Day19自定义 useFormik 实现高性能表单处理
flutter·开源·harmonyos
恋猫de小郭2 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
一只大侠的侠7 小时前
Flutter开源鸿蒙跨平台训练营 Day 10特惠推荐数据的获取与渲染
flutter·开源·harmonyos
renke336410 小时前
Flutter for OpenHarmony:色彩捕手——基于HSL色轮与感知色差的交互式色觉训练系统
flutter