先上代码
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: BodyWidget(),
),
),
);
}
}
class BodyWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return BodyWidgetState();
}
}
class BodyWidgetState extends State<BodyWidget> {
int count = 0;
@override
Widget build(BuildContext context) {
print("BodyWidgetState build:$hashCode");
return CustomInheritedWidget(
data: count,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
DependOnInheritedWidget<int>(),
Builder(builder: (context) {
return CustomRaisedButton(
onPressed: () {
setState(() {
count++;
});
},
child: Text("数字+1"),
);
})
],
),
);
}
}
class CustomRaisedButton extends RaisedButton {
const CustomRaisedButton({
@required VoidCallback onPressed,
Widget child,
}) : super(onPressed: onPressed, child: child);
@override
Widget build(BuildContext context) {
print("CustomRaisedButton build:$hashCode");
return super.build(context);
}
}
class DependOnInheritedWidget<T> extends StatefulWidget {
DependOnInheritedWidget(){
print("DependOnInheritedWidget:$hashCode");
}
@override
State<StatefulWidget> createState() {
return DependOnInheritedWidgetState<T>();
}
}
class DependOnInheritedWidgetState<T> extends State<DependOnInheritedWidget> {
@override
Widget build(BuildContext context) {
print("DependOnInheritedWidgetState build:$hashCode");
return Text(CustomInheritedWidget.of<T>(context).data.toString());
}
@override
void didChangeDependencies() {
print("DependOnInheritedWidgetState didChangeDependencies:$hashCode");
super.didChangeDependencies();
}
}
class CustomInheritedWidget<T> extends InheritedWidget {
CustomInheritedWidget({Key key, this.data, Widget child}) : super(key: key, child: child);
final T data;
//定义一个便捷方法,方便子树中的widget获取共享数据
static CustomInheritedWidget<T> of<T>(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget<T>>();
}
@override
bool updateShouldNotify(CustomInheritedWidget oldWidget) {
return oldWidget.data != data;
}
}
刚开始时,文本为0,当点击按钮的时候,数值+1并刷新页面,这时后台新增打印如下:
I/flutter (24452): BodyWidgetState build:293287865
I/flutter (24452): DependOnInheritedWidget:698685804
I/flutter (24452): DependOnInheritedWidgetState didChangeDependencies:185018106
I/flutter (24452): DependOnInheritedWidgetState build:185018106
I/flutter (24452): CustomRaisedButton build:266734984
通过打印的日志我们会发现DependOnInheritedWidgetState
调用了didChangeDependencies()
方法,我们来分析一下,点击按钮的时候都发生了什么。
_inheritedWidgets
的传递
首先说一下流程,在Element
被activate
和mount
的时候,会调用_updateInheritance
方法,把自己的_inheritedWidgets
指向_parent
的_inheritedWidgets
,而InheritedElement
覆盖了该方法,代码分别如下
mount()
是首次把element
添加到element Tree
后,然后element
变为active
状态。activate()
是把deactivate element
重新标记为active
状态。 总之是从无到有或者从不可见到可见。
//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树是这样的
BodyWidget
-CustomInheritedWidget
--Column
---DependOnInheritedWidget
---Builder
----CustomRaisedButton
CustomInheritedWidget
拷贝了BodyWidget
的_inheritedWidgets
到自己的_inheritedWidgets
并将自己保存其中,然后Column
、DependOnInheritedWidget
、Builder
、CustomRaisedButton
的_inheritedWidgets
直接指向了CustomInheritedWidget
的_inheritedWidgets
InheritedElement
的查找
在DependOnInheritedWidgetState
里调用CustomInheritedWidget.of
方法,of
方法调用context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget<T>>()
可以查找到CustomInheritedWidget
,代码如下:
//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
变量里,然后在自己(DependOnInheritedWidget
)的_dependencies
集合中添加ancestor
,并把自己保存到找到ancestor
的_dependents
集合里,这样在InheritedElement
更新内部数据的时候,就可以通知到所有依赖了本InheritedElement
的Widget
。同时DependOnInheritedWidget
的_dependencies
集合中添加了ancestor
,所以在DependOnInheritedWidget
销毁的时候,可以把自己(DependOnInheritedWidget
)从ancestor
的_dependents
集合中移除,避免不必要的更新和内存泄漏。
总结
总结一下上面的内容,在Element
被activate
和mount
的时候,会调用_updateInheritance
方法,把自己的_inheritedWidgets
指向_parent
的_inheritedWidgets
,而InheritedElement
覆盖了该方法,将自己保存到了_inheritedWidgets
中,所以在层层向下传递的时候,_inheritedWidgets
就包含了传递过程中所有的InheritedElement
,然后在通过dependOnInheritedWidgetOfExactType
方法获取InheritedElement
的时候,方法调用方把自己保存到了InheritedElement
的_dependencies
集合中,并且方法调用方在自己的_dependencies
集合中也添加了自己所依赖的InheritedElement
的引用,在方法调用方销毁的时候,把自己从自己所依赖的InheritedElement
的_dependencies
集合中删除自己,避免不必要的更新和内存泄漏。
思考题
Element
的activate
和mount
方法在什么时候被调用?- 在
CustomInheritedWidget
改变内部的数据的时候,为什么DependOnInheritedWidgetState
会调用didChangeDependencies()
?