1跨组件传递数据
总览
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;
}
/// 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_跨组件传递数据