inheritedWidget是如何实现数据共享的?
要解决这个问题,首先我们先看下,这个数据是如何存取的,又是如何刷新的.
一. _inheritedWidgets的存取
这个问题的奥秘其实就在Element中.

我们先来看一下inheritedWidget数据共享使用过程中的这个Map存取:
取:
通常我们使用inheritedWidget的时候,都是会有一个取数据的过程,这个时候我们会通过子节点的BuildContext(Element是BuildContext的实现类,使用context.getElementForInheritedWidgetOfExactType() 或 context.dependOnInheritedWidgetOfExactType来获取到这个widget或element从而获取到数据(例如上次讲的例子).

查看这两个方法,在Element中,都是从 _inheritedWidgets这个map里取值,泛型T是key

存:

InhertiedElement中重写了这个_updateInheritance()方法:
若父节点的_inheritedWidgets不为空,将其深拷贝给子节点的_inheritedWidgets;
若父节点的_inheritedWidgets为空,初始化一个Map,key为其widget的runtimeType

我们可以看到,element中有Map<Type, InheritedElement>? _inheritedWidgets成员变量,这个成员变量一般情况下是空的,只有当父控件或本身是InheritedWidget的时候, _inheritedWidgets才会被初始化.
当父控件是InheritedWidget是,这个Map会在Element中被一级一级的向下传递与合并.

二. dependOnInheritedWidgetOfExactType方法中到底做了什么
通过element中对此方法的描述及InheritedElement中此方法的实现,可以看出:
- 1. 从_inheritedWidgets中查找是否有该类型的InheritedElement
-
2. 查找到有的话,执行dependOnInheritedElement方法,将它添加到_dependencies里面; 并且调用ancestor.updateDependencies(this, aspect), 将当前Element添加到_dependents(Map<Element, Object?> _dependents)里面
Element中.png
image.png
image.png
image.png
- 3.返回这个element对应的widget (dependOnInheritedElement方法中)
三. getElementForInheritedWidgetOfExactType与dependOnInheritedWidgetOfExactType的区别

通过上图我们也可以看出, 两个方法的主要区别在于, getElementForInheritedWidgetOfExactType是直接获取了_inheritedWidgets内的InheritedElement返回;而dependOnInheritedWidgetOfExactType在获取的过程中,还多做了一步_dependents的管理,将_inheritedWidgets中的依赖关系管理起来
当inheritedWidget被更新时, _dependents中的element会被逐个执行notifyDependent,最后触发markNeedsBuild进行重绘.



当执行notifyDependent时,会触发Element的didChangeDependencies方法,将_didChangeDependencies置为true,从而触发State的didChangeDependencies的回调生命周期


总结
所以,当我们inheritedWidget来实现数据共享的时候,需要注意两个点
- 1.使用的context,必须是inheritedWidget的child widget对应的context---(Element)
- 2.getElementForInheritedWidgetOfExactType和dependOnInheritedWidgetOfExactType的区别
网友评论