import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter InheritWidget',
home: Scaffold(
appBar: AppBar(),
body: Center(
child: TestWidget(),
),
),
);
}
}
class TestWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return TestWidgetState();
}
}
class TestWidgetState extends State<TestWidget> {
String text = "init";
@override
Widget build(BuildContext context) {
return CustomInheritedWidget(
text: text,//1
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
InheritedWidgetChild(),
RaisedButton(
onPressed: () {
setState(() {
text = "modify";//2
});
},
child: Text("修改值"),
)
],
),
);
}
}
class InheritedWidgetChildState extends State<InheritedWidgetChild> {
@override
Widget build(BuildContext context) {
print("build");
final CustomInheritedWidget widget = context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget>();
return Text(widget.text);
}
@override
void didChangeDependencies() {
print("didChangeDependencies");
super.didChangeDependencies();
}
}
class CustomInheritedWidget extends InheritedWidget {
CustomInheritedWidget({Key key, this.text, Widget child}) : super(key: key, child: child);
final String text;
@override
bool updateShouldNotify(CustomInheritedWidget oldWidget) {
return oldWidget.text != text;
}
}
复制代码
init
,当点击按钮的时候,修改text值为
modify
并刷新页面,咱们会发现
InheritedWidgetChild
调用了
didChangeDependencies()
方法,咱们来分析一下,点击按钮的时候都发生了什么。
_inheritedWidgets
的传递首先说一下流程,在Element
被activate
和mount
的时候,会调用_updateInheritance
方法,把本身的_inheritedWidgets
指向_parent
的_inheritedWidgets
,而InheritedElement
覆盖了该方法,代码分别以下app
//Element
void _updateInheritance() {
assert(_active);
_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[widget.runtimeType] = this;
}
复制代码
能够看到InheritedElement
拷贝了_parent
的_inheritedWidgets
并把本身的 widget
的runtimeType
做为key
,this
做为value
保存在了本身的inheritedWidgets
属性里,因此最开始的代码的UI树是这样的less
TestWidgetide
-CustomInheritedWidgetui
--Columnthis
---InheritedWidgetChildspa
---RaisedButtondebug
CustomInheritedWidget
拷贝了TestWidget
的_inheritedWidgets
到本身的_inheritedWidgets
并将本身保存其中,而后Column
的_inheritedWidgets
直接指向了CustomInheritedWidget
的_inheritedWidgets
,而后InheritedWidgetChild
和RaisedButton
的_inheritedWidgets
直接指向了Column
的_inheritedWidgets
code
InheritedElement
的查找在InheritedWidgetChild
里调用context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget>()
方法能够查找到CustomInheritedWidget
,代码以下:cdn
//Element
@override
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;
}
复制代码
//InheritedElement
@protected
void updateDependencies(Element dependent, Object aspect) {
setDependencies(dependent, null);
}
@protected
void setDependencies(Element dependent, Object value) {
_dependents[dependent] = value;
}
复制代码
咱们能够看到,在dependOnInheritedWidgetOfExactType
这个方法里,查找到泛型Widget
对应的InheritedElement
,保存到ancestor
变量里,而后在本身(InheritedWidgetChild
)的_dependencies
集合中添加ancestor
,并把本身保存到找到ancestor
的_dependents
集合里,这样在InheritedElement
更新内部数据的时候,就能够通知到全部依赖了本InheritedElement
的Widget
。同时InheritedWidgetChild
的_dependencies
集合中添加了ancestor
,因此在InheritedWidgetChild
销毁的时候,能够把本身(InheritedWidgetChild
)从ancestor
的_dependents
集合中移除,避免没必要要的更新和内存泄漏。blog
总结一下上面的内容,在Element
被activate
和mount
的时候,会调用_updateInheritance
方法,把本身的_inheritedWidgets
指向_parent
的_inheritedWidgets
,而InheritedElement
覆盖了该方法,将本身保存到了_inheritedWidgets
中,因此在层层向下传递的时候,_inheritedWidgets
就包含了传递过程当中全部的InheritedElement
,而后在经过dependOnInheritedWidgetOfExactType
方法获取InheritedElement
的时候,方法调用方把本身保存到了InheritedElement
的_dependencies
集合中,而且方法调用方在本身的_dependencies
集合中也添加了本身所依赖的InheritedElement
的引用,在方法调用方销毁的时候,把本身从本身所依赖的InheritedElement
的_dependencies
集合中删除本身除,避免没必要要的更新和内存泄漏。
Element
的activate
和mount
方法在何时被调用?CustomInheritedWidget
改变内部的数据的时候,为何InheritedWidgetChild
会调用didChangeDependencies()
?