InheritedNotifier
scala
abstract class InheritedNotifier<T extends Listenable> extends InheritedWidget {
/// Create an inherited widget that updates its dependents when [notifier]
/// sends notifications.
///
/// The [child] argument must not be null.
const InheritedNotifier({
super.key,
this.notifier,
required super.child,
});
/// The [Listenable] object to which to listen.
///
/// Whenever this object sends change notifications, the dependents of this
/// widget are triggered.
///
/// By default, whenever the [notifier] is changed (including when changing to
/// or from null), if the old notifier is not equal to the new notifier (as
/// determined by the `==` operator), notifications are sent. This behavior
/// can be overridden by overriding [updateShouldNotify].
///
/// While the [notifier] is null, no notifications are sent, since the null
/// object cannot itself send notifications.
final T? notifier;
@override
bool updateShouldNotify(InheritedNotifier<T> oldWidget) {
return oldWidget.notifier != notifier;
}
@override
InheritedElement createElement() => _InheritedNotifierElement<T>(this);
}
InheritedNotifier
是InheritedWidget
的一个变体, 跟ChangeNotifier
类一样, 是Listenable
的一个子类。
通常来讲, 这个类的子类是一个提供of
静态的类调用BuildContext.dependOnInheritedWidgetOfExactType
的方法类, 如下:
javascript
static SubclassedNotifier of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<SubclassedNotifier>()!;
}
读取当前子类SubclassedNotifier
javascript
static SubclassedNotifier read(BuildContext context) {
return context.getInheritedWidgetOfExactType<SubclassedNotifier>()!;
}
T? notifier
接收要监听的Listenable
对象。当这个notifier
对象发送变更通知时,这个对象的依赖项组件被触发。
child
接受外部传进来的叶子节点。
_InheritedNotifierElement
scala
class _InheritedNotifierElement<T extends Listenable> extends InheritedElement {
_InheritedNotifierElement(InheritedNotifier<T> widget) : super(widget) {
widget.notifier?.addListener(_handleUpdate);
}
bool _dirty = false;
@override
void update(InheritedNotifier<T> newWidget) {
final T? oldNotifier = (widget as InheritedNotifier<T>).notifier;
final T? newNotifier = newWidget.notifier;
if (oldNotifier != newNotifier) {
oldNotifier?.removeListener(_handleUpdate);
newNotifier?.addListener(_handleUpdate);
}
super.update(newWidget);
}
@override
Widget build() {
if (_dirty) {
notifyClients(widget as InheritedNotifier<T>);
}
return super.build();
}
void _handleUpdate() {
_dirty = true;
markNeedsBuild();
}
@override
void notifyClients(InheritedNotifier<T> oldWidget) {
super.notifyClients(oldWidget);
_dirty = false;
}
@override
void unmount() {
(widget as InheritedNotifier<T>).notifier?.removeListener(_handleUpdate);
super.unmount();
}
}
_InheritedNotifierElement
的初始化构造方法中, 给对象notifier
添加一个监听回调_handleUpdate
方法。
_handleUpdate
方法首先_dirty=true
标记为脏
, 并且触发markNeedsBuild
, 直到触发build
方法。
build
方法中, 如果_dirty=true
, 那么, 调用notifyClients
方法通知依赖者。
notifyClients
方法中, 依赖者也随即触发markNeedsBuild
, 进而重新构建自己的child
, 并标记_dirty=false
。
通知对象notifier
, 在外部调用notifyListeners()
方法时, 会触发监听者addListener
回调_handleUpdate
方法。
那末, notifyClients
方法是怎样通知依赖者的呢?接下来, 我们一起阅读_InheritedNotifierElement
的父类InheritedElement
的源码。
InheritedElement
typescript
class InheritedElement extends ProxyElement {
/// Creates an element that uses the given widget as its configuration.
InheritedElement(InheritedWidget super.widget);
final Map<Element, Object?> _dependents = HashMap<Element, Object?>();
@override
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
final PersistentHashMap<Type, InheritedElement> incomingWidgets =
_parent?._inheritedElements ?? const PersistentHashMap<Type, InheritedElement>.empty();
_inheritedElements = incomingWidgets.put(widget.runtimeType, this);
}
@override
void debugDeactivated() {
assert(() {
assert(_dependents.isEmpty);
return true;
}());
super.debugDeactivated();
}
/// Returns the dependencies value recorded for [dependent]
/// with [setDependencies].
///
/// Each dependent element is mapped to a single object value
/// which represents how the element depends on this
/// [InheritedElement]. This value is null by default and by default
/// dependent elements are rebuilt unconditionally.
///
/// Subclasses can manage these values with [updateDependencies]
/// so that they can selectively rebuild dependents in
/// [notifyDependent].
///
/// This method is typically only called in overrides of [updateDependencies].
///
/// See also:
///
/// * [updateDependencies], which is called each time a dependency is
/// created with [dependOnInheritedWidgetOfExactType].
/// * [setDependencies], which sets dependencies value for a dependent
/// element.
/// * [notifyDependent], which can be overridden to use a dependent's
/// dependencies value to decide if the dependent needs to be rebuilt.
/// * [InheritedModel], which is an example of a class that uses this method
/// to manage dependency values.
@protected
Object? getDependencies(Element dependent) {
return _dependents[dependent];
}
/// 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].
///
/// This method is typically only called in overrides of [updateDependencies].
///
/// See also:
///
/// * [updateDependencies], which is called each time a dependency is
/// created with [dependOnInheritedWidgetOfExactType].
/// * [getDependencies], which returns the current value for a dependent
/// element.
/// * [notifyDependent], which can be overridden to use a dependent's
/// [getDependencies] value to decide if the dependent needs to be rebuilt.
/// * [InheritedModel], which is an example of a class that uses this method
/// to manage dependency values.
@protected
void setDependencies(Element dependent, Object? value) {
_dependents[dependent] = value;
}
/// Called by [dependOnInheritedWidgetOfExactType] when a new [dependent] is added.
///
/// Each dependent element can be mapped to a single object value with
/// [setDependencies]. This method can lookup the existing dependencies with
/// [getDependencies].
///
/// By default this method sets the inherited dependencies for [dependent]
/// to null. This only serves to record an unconditional dependency on
/// [dependent].
///
/// Subclasses can manage their own dependencies values so that they
/// can selectively rebuild dependents in [notifyDependent].
///
/// See also:
///
/// * [getDependencies], which returns the current value for a dependent
/// element.
/// * [setDependencies], which sets the value for a dependent element.
/// * [notifyDependent], which can be overridden to use a dependent's
/// dependencies value to decide if the dependent needs to be rebuilt.
/// * [InheritedModel], which is an example of a class that uses this method
/// to manage dependency values.
@protected
void updateDependencies(Element dependent, Object? aspect) {
setDependencies(dependent, null);
}
/// Called by [notifyClients] for each dependent.
///
/// Calls `dependent.didChangeDependencies()` by default.
///
/// Subclasses can override this method to selectively call
/// [didChangeDependencies] based on the value of [getDependencies].
///
/// See also:
///
/// * [updateDependencies], which is called each time a dependency is
/// created with [dependOnInheritedWidgetOfExactType].
/// * [getDependencies], which returns the current value for a dependent
/// element.
/// * [setDependencies], which sets the value for a dependent element.
/// * [InheritedModel], which is an example of a class that uses this method
/// to manage dependency values.
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
dependent.didChangeDependencies();
}
/// Calls [Element.didChangeDependencies] of all dependent elements, if
/// [InheritedWidget.updateShouldNotify] returns true.
///
/// Called by [update], immediately prior to [build].
///
/// Calls [notifyClients] to actually trigger the notifications.
@override
void updated(InheritedWidget oldWidget) {
if ((widget as InheritedWidget).updateShouldNotify(oldWidget)) {
super.updated(oldWidget);
}
}
/// Notifies all dependent elements that this inherited widget has changed, by
/// calling [Element.didChangeDependencies].
///
/// This method must only be called during the build phase. Usually this
/// method is called automatically when an inherited widget is rebuilt, e.g.
/// as a result of calling [State.setState] above the inherited widget.
///
/// See also:
///
/// * [InheritedNotifier], a subclass of [InheritedWidget] that also calls
/// this method when its [Listenable] sends a notification.
@override
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);
}
}
}
notifyClients
方法里面, 获取Map
对象_dependents
所有的key
, 并循环遍历.
通过调用notifyDependent
方法, 再执行didChangeDependencies
, 随机执行markNeedsBuild
,告知所有依赖的元素, 这个inherited widget
已经发生了改变。
updateDependencies
文章开头声明的of静态的类
调用dependOnInheritedWidgetOfExactType
时,就会updateDependencies
、setDependencies
方法, 将一个新的依赖项dependent
添加_dependents
对象中。
BuildContext(抽象类)
提供添加依赖, 获取依赖的api
javascript
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
r
T? getInheritedWidgetOfExactType<T extends InheritedWidget>();
Element(BuildContext的实现类)
typescript
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget as InheritedWidget;
}
@override
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor = _inheritedElements == null ? null : _inheritedElements![T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
真正的实现添加依赖项。
r
@override
T? getInheritedWidgetOfExactType<T extends InheritedWidget>() {
return getElementForInheritedWidgetOfExactType<T>()?.widget as T?;
}
获取依赖项。