1跨组件传递数据

总览

image

InheritedWidget图解

graph TB
parent("parentInheritedWidget")-->|_dependents:依赖我,的组件,也就是我的改变需要通知到的组件|child("child.inheritFromWidgetOfExactType")
child-->|getParentInheritedWidget|parent
child-->|useParentInheritedWidget|child

类设计

Element.mount

@mustCallSuper
 void mount(Element parent, dynamic newSlot) {
   _updateInheritance();//main
 }

InheritedElement._updateInheritance

@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[widget.runtimeType] = this;
 }

Element.inheritFromWidgetOfExactType

  /// Obtains the nearest widget of the given type, which must be the type of a
  /// concrete [InheritedWidget] subclass, and registers this build context with
  /// that widget such that when that widget changes (or a new widget of that
  /// type is introduced, or the widget goes away), this build context is
  /// rebuilt so that it can obtain new values from that widget.
  ///
  /// This method is deprecated. Please use [dependOnInheritedWidgetOfExactType] instead.
  // TODO(a14n): Remove this when it goes to stable, https://github.com/flutter/flutter/pull/44189
@override
 InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect }) {//继承自BuildContext
  assert(_debugCheckStateIsActiveForAncestorLookup());
  final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
  if (ancestor != null) {
   assert(ancestor is InheritedElement);
   return inheritFromElement(ancestor, aspect: aspect);
  }
  _hadUnsatisfiedDependencies = true;
  return null;
 }
@override
 InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
  return dependOnInheritedElement(ancestor, aspect: aspect);
 }
@override
 InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
  assert(ancestor != null);
  _dependencies ??= HashSet<InheritedElement>();
  _dependencies.add(ancestor);
  ancestor.updateDependencies(this, aspect);
  return ancestor.widget;
 }

ancestor.updateDependencies

/// Subclasses can manage their own dependencies values so that they
/// can selectively rebuild dependents in [notifyDependent].
@protected
 void updateDependencies(Element dependent, Object aspect) {
  setDependencies(dependent, null);
 }
/// Sets the value returned by [getDependencies] value for [dependent].
 ///
 /// Each dependent element is mapped to a single object value
 /// which represents how the element depends on this
 /// [InheritedElement]. The [updateDependencies] method sets this value to
 /// null by default so that dependent elements are rebuilt unconditionally.
 ///
 /// Subclasses can manage these values with [updateDependencies]
 /// so that they can selectively rebuild dependents in [notifyDependent].
@protected
 void setDependencies(Element dependent, Object value) {
  _dependents[dependent] = value;
 }

InheritedElement.notifyClients

/// Notifies all dependent elements that this inherited widget has changed, by
 /// calling [Element.didChangeDependencies].
@override
 void notifyClients(InheritedWidget oldWidget) {
for (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);//main
 }
//通知依赖我,的组件(childWidgets),我的变换需要通知到它们
@protected
 void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
  dependent.didChangeDependencies();//默认调用Element的markNeedsBuild(),rebuild时如果_dirty为false则直接return不会performRebuild()
}

notifyClients调用时机

//InheritedElement extends ProxyElement
//performBuild-->updateChild-->update
ProxyElement {
    @override
  void update(ProxyWidget newWidget) {
    final ProxyWidget oldWidget = widget;
    assert(widget != null);
    assert(widget != newWidget);
    super.update(newWidget);
    assert(widget == newWidget);
    updated(oldWidget);//main
    _dirty = true;
    rebuild();
  }
}

  @protected
  void updated(covariant ProxyWidget oldWidget) {
    notifyClients(oldWidget);
  }

Notification图解

graph TB
parent("parentNotificationListener")-->|ignoreThisArrow|child
child-->|dispatch|parent-->|_dispatchWithParaNotification|parent

dispatch

/// A notification that can bubble up the widget tree.
 ///
 /// You can determine the type of a notification using the `is` operator to
 /// check the [runtimeType] of the notification.
 ///
 /// To listen for notifications in a subtree, use a [NotificationListener].
 ///
 /// To send a notification, call [dispatch] on the notification you wish to
 /// send. The notification will be delivered to any [NotificationListener]
 /// widgets with the appropriate type parameters that are ancestors of the given
 /// [BuildContext].
Notification {
  void dispatch(BuildContext target) {
  target?.visitAncestorElements(visitAncestor);
 }

bool visitAncestor(Element element) {
  if (element is StatelessElement) {
   final StatelessWidget widget = element.widget;
   if (widget is NotificationListener<Notification>) {
    if (widget._dispatch(this, element)) // that function checks the type dynamically
     return false;
   }
  }
  return true;
 }
}

Element.visitAncestorElements

@override
 void visitAncestorElements(bool visitor(Element element)) {//继承自BuildContext
  assert(_debugCheckStateIsActiveForAncestorLookup());
  Element ancestor = _parent;
  while (ancestor != null && visitor(ancestor))
   ancestor = ancestor._parent;
 }

NotificationListener._dispatch

class NotificationListener<T extends Notification> extends StatelessWidget {
 /// Return true to cancel the notification bubbling. Return false (or null) to
 /// allow the notification to continue to be dispatched to further ancestors.

final NotificationListenerCallback<T> onNotification;

bool _dispatch(Notification notification, Element element) {
  if (onNotification != null && notification is T) {
   final bool result = onNotification(notification);
   return result == true; // so that null and false have the same effect
  }
  return false;
 }
}

参考

InheritedNotifier, InheritedModel

flutter_15_跨组件传递数据