作用

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方法,InheritedElementupdateDependencies方法,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的重建通知。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注