Wechat official account: Android blog, with qr code at the end of the article

Personal website: chengang.plus

1, usage,

Usage Examples:

class InheritedData extends InheritedWidget {
  final String data;

  InheritedData({
    this.data,
    Widget child,
  }) : super(child: child);

  static InheritedData of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<InheritedData>();
  }

  @override
  bool updateShouldNotify(InheritedData old) => true;
}

class TestInheritedDataWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        "${InheritedData.of(context).data}",
        style: TextStyle(fontSize: 18, color: Colors.pink), ), ); }}class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  var data = "you are beautiful";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        child: Container(
          color: Colors.cyan,
          width: double.infinity,
          child: InheritedData(
            data: data,
            child: TestInheritedDataWidget(),
          ),
        ),
        onTap: _buttonClicked,
      ),
    );
  }

  _buttonClicked() {
    setState(() {
      data = "in white"; }); }}Copy the code

2, ProxyWidget

InheritedWidget inherits from the ProxyWidget, and creates an InheritedElement object when createElement is called in the ProxyWidget.

2.1 InheritedElement

InheritedElement inherits from ProxyElement, InheritedElement inherits from ComponentElement, and ComponentElement inherits from Element.

InheritedElement defines a global Map object within the InheritedElement:

final Map<Element.Object> _dependents = HashMap<Element.Object> ();Copy the code

An _updateInheritance method is also defined. There is a definition in both Element and InheritedElement:

Element

void_updateInheritance() { _inheritedWidgets = _parent? ._inheritedWidgets; }Copy the code

Map

_inheritedWidgets defined in Element is a global variable.
,>

InheritedElement

@override
void _updateInheritance() {
    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;
}
Copy the code

The primary logic of this method in InheritedElement is: If the existing Element exists, create a new one. Otherwise, add the existing Element to the _inheritedWidgets and add the current Element to the _inheritedWidgets.

The _updateInheritance method in Element is executed meaning that all the widgets corresponding to the Element hold an _inheritedWidgets, An InheritedWidget’s child can hold an InheritedElement directly via Element’s _updateInheritance method.

2.2 Save the InheritedElement node

So where does _updateInheritance get called?

Refer to the previous article on the Flutter Drawing Process series 2- Layout. In the Mount method of the Element class, the _updateInheritance method is called, which ends up here.

3. Update in ProxyElement

When the data in the InheritedWidget is updated by setState, the data-dependent Widget is updated as well.

3.1 ProxyElement Update method

@override
void update(ProxyWidget newWidget) {
    final ProxyWidget oldWidget = widget;
    super.update(newWidget);
    updated(oldWidget);
    _dirty = true;
    rebuild();
}
Copy the code

To the updated method, in the InheritedElement method:

InheritedElement

@override
void updated(InheritedWidget oldWidget) {
    if (widget.updateShouldNotify(oldWidget))
      super.updated(oldWidget);
}
Copy the code

If updateShouldNotify returns true in our InheritedWidget, we execute the updated method on our InheritedElement:

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

NotifyClients executes the notifyClients method on the InheritedElement in the subclass.

3.2 InheritedElement notifyClients method

@override
void notifyClients(InheritedWidget oldWidget) {
    for (final Element dependent in_dependents.keys) { notifyDependent(oldWidget, dependent); }}Copy the code

This _dependents holds a node that relies on the InheritedWidget data.

3.3 _dependents Saves the Element that depends on the data

In the beginning of this chapter InheritedData provides a method of static, dependent child widgets (InheritedWidget) call dependOnInheritedWidgetOfExactType method. Implemented in the Element class, BuildContext defines:

Element implements the BuildContext interface

Element

@override
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {
    final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
    if(ancestor ! =null) {
      return dependOnInheritedElement(ancestor, aspect: aspect) as T;
    }
    _hadUnsatisfiedDependencies = true;
    return null;
}
Copy the code

Here we find the InheritedElement, and find the value (InheritedElement) using the _inheritedWidgets key (runtimeType). Next call the dependOnInheritedElement method:

Element

@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Objectaspect }) { _dependencies ?? = HashSet<InheritedElement>(); _dependencies.add(ancestor); ancestor.updateDependencies(this, aspect);
    return ancestor.widget;
}
Copy the code

In the Element class, determine if _dependencies is empty, create a HashSet, add the InheritedElement to it, and then execute the updateDependencies method. This refers to the Element of the InheritedWidget’s child Widget.

The updateDependencies are defined in the corresponding InheritedElement class:

InheritedElement

@override
void updateDependencies(Element dependent, Object aspect) {
    final Set<T> dependencies = getDependencies(dependent) as Set<T>;
    if(dependencies ! =null && dependencies.isEmpty)
      return;
    
    if (aspect == null) {
      setDependencies(dependent, HashSet<T>());
    } else{ setDependencies(dependent, (dependencies ?? HashSet<T>()).. add(aspectasT)); }}@protected
void setDependencies(Element dependent, Object value) {
    _dependents[dependent] = value;
}
Copy the code

An _dependents Element is stored in the child Widget of the InheritedWidget.

3.4 Remind dependent Element updates

Return to the InheritedElement notifyClients method, which iterates over _dependents and executes notifyDependent:

InheritedElement

@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
    dependent.didChangeDependencies();
}

@mustCallSuper
void didChangeDependencies() {
    markNeedsBuild();
}
Copy the code

Go here to redraw widgets that rely on the InheritedWidget data.