Flutter InheritedWidget源码解析
作用
InheritedWidget
是一个在Widget
树中,从上往下传递信息的小部件。
主要从两个方面理解源码:
1.子Widget
可以获取到父控件中的InheritedWidget
,从而获取到InheritedWidget的信息。
2.子Widget
调用dependOnInheritedWidgetOfExactType
后,当父InheritedWidget
重建后,会调用子控件重建。
原理
1.子控件可以获取到父控件中的InheritedWidget
在Element
中有个Map:
Map<Type, InheritedElement> _inheritedWidgets;
其中保存了该Widget
的父节点中的InheritedWidget
。会在mount
\activate
方法中赋值,赋值的代码如下:
在Element
中
void _updateInheritance() { assert(_active); //获取到父节点的_inheritedWidgets _inheritedWidgets = _parent?._inheritedWidgets; }
在InheritedElement
中
@override void _updateInheritance() { assert(_active); final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets; if (incomingWidgets != null) _inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets); else _inheritedWidgets = HashMap<Type, InheritedElement>(); //将自身保存在_inheritedWidgets中 _inheritedWidgets[widget.runtimeType] = this; }
经过上面两个方法,Widget
本身就可以通过_inheritedWidgets
获取到InheritedElement
了
2.子Widget
调用dependOnInheritedWidgetOfExactType
后,当父InheritedWidget
重建后,会调用子控件重建
在InheritedElement
中有个Map:
final Map<Element, Object> _dependents = HashMap<Element, Object>();
当子Widget
调用dependOnInheritedWidgetOfExactType
方法时,会依次调用dependOnInheritedElement
方法,InheritedElement
的updateDependencies
方法,setDependencies
方法。将自己注册到父InheritedElement
的_dependents
中。
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) { assert(_debugCheckStateIsActiveForAncestorLookup()); final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T]; if (ancestor != null) { assert(ancestor is InheritedElement); return dependOnInheritedElement(ancestor, aspect: aspect) as T; } _hadUnsatisfiedDependencies = true; return null; } @override InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) { assert(ancestor != null); _dependencies ??= HashSet<InheritedElement>(); _dependencies.add(ancestor); ancestor.updateDependencies(this, aspect); return ancestor.widget; } @protected void updateDependencies(Element dependent, Object aspect) { setDependencies(dependent, null); } @protected void setDependencies(Element dependent, Object value) { _dependents[dependent] = value; }
当InheritedElement
重建时会调用updated
方法,然后会调用到notifyClients
方法,最终调用Widget didChangeDependencies
方法并重建子Widget
。
void updated(InheritedWidget oldWidget) { if (widget.updateShouldNotify(oldWidget)) super.updated(oldWidget); } void notifyClients(InheritedWidget oldWidget) { assert(_debugCheckOwnerBuildTargetExists('notifyClients')); for (final Element dependent in _dependents.keys) { assert(() { // check that it really is our descendant Element ancestor = dependent._parent; while (ancestor != this && ancestor != null) ancestor = ancestor._parent; return ancestor == this; }()); // check that it really depends on us assert(dependent._dependencies.contains(this)); notifyDependent(oldWidget, dependent); } } void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) { dependent.didChangeDependencies(); }
由上边的代码可以看出,只有当子Widget调用了dependOnInheritedWidgetOfExactType才会收到InheritedWidget的重建通知。