共计 17576 个字符,预计需要花费 44 分钟才能阅读完成。
老孟导读:这是 2021 年源码系列的第一篇文章,其实源码系列的文章不是特地受欢迎,一个起因是原理性的常识十分干燥,我本人看源码的时候特地有感触,二是想把源码剖析讲的通俗易懂十分艰难,本人明确 和 让他人听懂齐全是两回事。不过我仍然会保持 Flutter 源码系列的文章,进步本人的技术水平的同时,也心愿大家播种一些常识。
为了使源码系列的文章不那么干燥,文章中会有很多流程图,流程图比纯文字更直观,一图胜千言。
我也是第一次写源码系列的文章,如果文章哪里有不对的中央请通知我,尽管我也不肯定听????,开个玩笑。
心愿大家来个 赞 ,您的 赞是我写下去的微小能源????。
所有源码系列文章都会分享到我集体博客:http://laomengit.com/
注释
留神:应用的 Flutter 版本 和 Dart 版本如下:
Flutter 1.22.4 • channel stable • https://github.com/flutter/fl…
Framework • revision 1aafb3a8b9 (6 weeks ago) • 2020-11-13 09:59:28 -0800
Engine • revision 2c956a31c0
Tools • Dart 2.10.4不同的版本可能有所不同,请留神版本之间的区别。
首先,InheritedWidget 是一个 十分重要 , 十分重要 , 十分重要 的组件,重要的事件说 3 遍????,零碎中很多性能都是功能型组件都是通过 InheritedWidget 实现的,驰名的 Provider 状态治理框架也是基于 InheritedWidget 实现的,因而不论是工作中,还是面试,InheritedWidget 组件的原理及应用场景都是考查的重点。
此篇文章包含如下几个局部:
- InheritedWidget 组件简介,是什么场景下应用 InheritedWidget?
- InheritedWidget 根本用法。
- InheritedWidget 源码剖析。
InheritedWidget 组件简介
InheritedWidget 组件是功能型组件,提供了 沿树向下,共享数据 的性能,即子组件能够获取父组件 (InheritedWidget 的子类) 的数据,通过BuildContext.dependOnInheritedWidgetOfExactType 获取。
InheritedWidget 组件的共享数据是沿着树从上到下,是否联想到 Notification,Notification 正好与 InheritedWidget 传递方向相同,Notification 是沿着树从下到上,两者性能的实现都是子节点被动发动,InheritedWidget 组件的子节点被动查找父节点上 InheritedWidget 共享的数据,Notification 也是子节点被动发动告诉,沿着树向上告诉。
Notification 也是 Flutter 中十分重要的,前面会有专门的文章具体介绍,此篇不做介绍。
那么什么样的场景适宜应用 InheritedWidget 呢? 通常 App 会有登录用户信息,登录用户信息为全局共享信息,设想一下,子组件要如何获取登录用户信息?将下面的场景形象一下,有一颗组件树,A、H 组件依赖同一数据,如下:
A、H 组件要如何获取到数据呢?
有一种实现形式是 通过构造函数透传,数据通过 A 传递给 B,B 传递给 C、E,C 和 E 在传递给 F、H,如下图虚线的传递:
反馈到代码上就是:
return A(
data:data
child:B(
data:data
child:C(
data:data
child:F(data:data)
)
)
);
这样的实现毛病非常明显,B、C 组件不须要 data 数据,如果组件树比拟深的话,那将是噩梦。
为了解决此问题,Flutter Framework 提供了 InheritedWidget 组件,InheritedWidget 组件的子组件能够间接获取数据,如下图:
InheritedWidget 组件的所有子组件都能够间接通过 BuildContext.dependOnInheritedWidgetOfExactType 获取数据。
InheritedWidget 根本用法
下面剖析了 InheritedWidget 组件的应用场景,上面用一个最简略的 demo 展现如何应用 InheritedWidget 组件。
定一个用户信息共享数据的实体类,任何子组件都能够获取用户信息,用户信息实体类:
class UserInfo {
String name;
int age;
UserInfo({this.name, this.age});
@override
bool operator ==(Object other) {if (!(other is UserInfo)) {return false;}
var old = other as UserInfo;
return name == old.name && age == old.age;
}
}
UserInfo 类重写了 == 操作符,是为了前面数据是否发生变化做判断。
定义共享 UserInfo 数据的 InheritedWidget 组件。
class MyInheritedWidget extends InheritedWidget {
final UserInfo userInfo;
MyInheritedWidget({this.userInfo, Widget child}):super(child: child);
static MyInheritedWidget of(BuildContext context) {return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
}
@override
bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {return oldWidget.userInfo != userInfo;}
}
这里有两个中央须要留神:
-
动态(static) of 办法,这个办法不是必须的,但个别都会增加此办法,不便其子组件调用,当然也能够间接在子组件中应用 context.dependOnInheritedWidgetOfExactType 办法,不加 of 办法,子组件调用如下:
class F extends StatelessWidget { @override Widget build(BuildContext context) { var myInheritedWidget = context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>(); return Text('name:${myInheritedWidget.userInfo.name}'); } }
增加动态(static) of 办法,用法如下:
class F extends StatelessWidget { @override Widget build(BuildContext context) {return Text('name:${MyInheritedWidget.of(context).userInfo.name}'); } }
咱们常常应用的 MediaQuery.of(context) 和 Theme.of(context) 办法都是零碎封装的此办法。
- updateShouldNotify 办法必须重写,此办法是判断新的共享数据和原数据是否统一,是否将告诉传递给所有子组件(已注册)。重建此组件时,有时须要重建继承 InheritedWidget 组件的组件,但有时不须要。例如,如果此组件所保留的数据与“oldWidget”所保留的数据雷同,则咱们无需重建继承了“oldWidget”所保留的数据的组件。
应用 MyInheritedWidget 组件:
class InheritedWidgetDemo extends StatefulWidget {
@override
_InheritedWidgetDemoState createState() => _InheritedWidgetDemoState();
}
class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Demo'),),body: Center(
child: MyInheritedWidget(userInfo: UserInfo(name: '老孟',age: 18),child: A(child: F(),),),),);
}
}
A 组件代码:
class A extends StatelessWidget {
final Widget child;
const A({Key key,this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(child: child,);
}
}
F 组件代码:
class F extends StatelessWidget {
@override
Widget build(BuildContext context) {return Text('name:${MyInheritedWidget.of(context).userInfo.name}');
}
}
下面代码形成的组件树为(无关的节点已疏忽比方 Scaffold、Center 等):
留神: A 组件是为了示意树的深度,此 Demo 中将其简化了,仅仅设置了一层,也能够设多多层。
运行成果:
上面批改数据并刷新 UI,上面的代码仅能用于 Demo,是为了演示不便,千万不要用于理论我的项目,因为上面的写法有微小的性能问题,因为重建了 InheritedWidget 组件下的所有子组件,重要的事件说 3 遍:上面演示 Demo 千万不要用于理论我的项目 , 千万不要用于理论我的项目 , 千万不要用于理论我的项目。文章最初我会给出正确用法。
批改 _InheritedWidgetDemoState:
class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {UserInfo _userInfo = UserInfo(name: '老孟', age: 18);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Demo'),
),
body: Center(
child: MyInheritedWidget(
userInfo: _userInfo,
child: A(child: F(),
),
),
),
floatingActionButton: FloatingActionButton(onPressed: () {setState(() {_userInfo = UserInfo(name: '老孟 1', age: 18);
});
},
),
);
}
}
点击按钮的时候,UI 刷新了,但请重点看右侧 rebuild stats 局部,每点击一次按钮,MyInheritedWidget 组件及其子组件全副 从新构建(rebuild),但 A 组件并不依赖于 MyInheritedWidget 共享数据,现实状况下不应该 rebuild,理论我的项目中,树的构造会比这个简单的多,因而全副 rebuild 会造成性能问题,这也是结尾说千万不要将此形式用于理论我的项目,网上充斥着大量此种用法的文章,前面会给出正确用法,正确用法比较复杂,而且波及其余相干常识,所以此处的 Demo 仅用于学习 InheritedWidget。
大家是否还记得 Stateful 组件的生命周期 文章中介绍的 didChangeDependencies 生命周期,对其的介绍如下:
didChangeDependencies 办法在 initState 之后由 Framework 立刻调用。另外,当此 State 对象的依赖项更改时被调用,比方其所依赖的 InheritedWidget 发生变化时,Framework 会调用此办法告诉组件发生变化。
上面将 A 和 F 组件改为 StatefulWidget 组件:
class F extends StatefulWidget {
@override
_FState createState() => _FState();
}
class _FState extends State<F> {
@override
void initState() {super.initState();
print('F initState');
}
@override
Widget build(BuildContext context) {print('F build');
return Text('name:${MyInheritedWidget.of(context).userInfo.name}');
}
@override
void didChangeDependencies() {super.didChangeDependencies();
print('F didChangeDependencies');
}
@override
void dispose() {super.dispose();
print('F dispose');
}
}
class A extends StatefulWidget {
final Widget child;
const A({Key key, this.child}) : super(key: key);
@override
_AState createState() => _AState();
}
class _AState extends State<A> {
@override
void initState() {super.initState();
print('A initState');
}
@override
Widget build(BuildContext context) {print('A build');
return Center(child: widget.child,);
}
@override
void didChangeDependencies() {super.didChangeDependencies();
print('A didChangeDependencies');
}
@override
void dispose() {super.dispose();
print('A dispose');
}
}
给各个生命周期增加日志打印,从新运行,点击按钮,输入日志如下:
flutter: A build
flutter: F didChangeDependencies
flutter: F build
因而,依赖 MyInheritedWidget 组件的 F 组件调用 didChangeDependencies 办法,而 A 组件没有调用 didChangeDependencies 办法,因为 A 没有依赖 MyInheritedWidget 组件。
上面再说一个非常容易疏忽的中央 MyInheritedWidget.updateShouldNotify办法,个别这样写:
@override
bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {return oldWidget.userInfo != userInfo;}
这样写有什么问题吗?如果数据(userInfo)是自定义的实体类且未在 UserInfo 中重写 ==,那么极大概率呈现有问题,因为不重写 == 操作符办法,应用 != 判断是否相等的时候判断的是两个对象的内存地址,上面将 UserInfo 中 == 办法去掉,
class UserInfo {
String name;
int age;
UserInfo({this.name, this.age});
}
批改 _InheritedWidgetDemoState 类:
class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {UserInfo _userInfo = UserInfo(name: '老孟', age: 18);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Demo'),
),
body: Center(
child: MyInheritedWidget(
userInfo: _userInfo,
child: A(child: F(),
),
),
),
floatingActionButton: FloatingActionButton(onPressed: () {setState(() {_userInfo = UserInfo(name: '老孟', age: 18);
});
},
),
);
}
}
批改 updateShouldNotify 办法,增加日志打印:
@override
bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {
bool flag = oldWidget.userInfo != userInfo;
print('updateShouldNotify:$flag');
return flag;
}
点击按钮,_userInfo 对象援用产生了变动,但其值(name 和 age)都没有发生变化,updateShouldNotify 应该返回 false,但理论打印的后果:
flutter: updateShouldNotify:true
flutter: A build
flutter: F didChangeDependencies
flutter: F build
理论返回了 true,因为前后 _userInfo 对象援用产生了变动,在 UserInfo 中重写 ==,比拟具体的 name 和 age 是否相等:
@override
bool operator ==(Object other) {if (!(other is UserInfo)) {return false;}
var old = other as UserInfo;
return name == old.name && age == old.age;
}
再次运行,日志如下:
flutter: updateShouldNotify:false
flutter: A build
flutter: F build
还有一种谬误写法:
class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {UserInfo _userInfo = UserInfo(name: '老孟', age: 18);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Demo'),
),
body: Center(
child: MyInheritedWidget(
userInfo: _userInfo,
child: A(child: F(),
),
),
),
floatingActionButton: FloatingActionButton(onPressed: () {setState(() {
_userInfo.name = '老孟 1';
// _userInfo = UserInfo(name: '老孟', age: 18);
});
},
),
);
}
}
重点看这部分批改:
floatingActionButton: FloatingActionButton(onPressed: () {setState(() {
_userInfo.name = '老孟 1';
// _userInfo = UserInfo(name: '老孟', age: 18);
});
},
),
将 _userInfo = UserInfo(name: ‘ 老孟 ’, age: 18) 批改为 _userInfo.name = ‘ 老孟 1 ’,猜猜 updateShouldNotify 返回是 true or false?
运行日志:
flutter: updateShouldNotify:false
flutter: A build
flutter: F build
是不是感觉十分不堪设想,两次的 name 值不一样啊?
那是因为 _userInfo.name = ‘ 老孟 1 ’ 也批改了 oldWidget 的_userInfo,前后两次都指向了同一个对象援用。
很多人应该会有这样一个疑难,假如设置 updateShouldNotify 返回 false,点击的时候 UI 也会更改,因为整颗树都 rebuild 了,那么 updateShouldNotify 由什么意义呢?
必定是有意义的,看如下场景,F 组件应用 InheritedWidget 的共享数据拜访服务器接口,获取服务器数据并展现,如果 updateShouldNotify 返回 false,那么 F 组件 rebuild 时只会执行 build 函数,而拜访服务器接口是一个耗时工作,思考性能因素,不能将拜访服务器接口放在 build 函数中,那么 InheritedWidget 数据的更新就无奈更新其依赖的组件,而 updateShouldNotify 返回 true 时,F 组件 rebuild 时会执行 didChangeDependencies 和 build 函数,此时能够将拜访服务器接口放在 didChangeDependencies 函数中,这也是 didChangeDependencies 生命周期存在的意义。
上面 重点来了,那么如何正确应用 InheritedWidget 组件,答案是 InheritedWidget + ValueNotifier,对于 ** 的用法能够到我的集体博客中查看,地址:http://laomengit.com/flutter/widgets/ValueListenableBuilder.html,这里不具体开展介绍。
批改 MyInheritedWidget 代码:
class MyInheritedWidget extends InheritedWidget {
ValueNotifier<UserInfo> _valueNotifier;
ValueNotifier<UserInfo> get valueNotifier => _valueNotifier;
MyInheritedWidget(UserInfo userInfo, {Widget child}) : super(child: child) {_valueNotifier = ValueNotifier<UserInfo>(userInfo);
}
static MyInheritedWidget of(BuildContext context) {return context.getElementForInheritedWidgetOfExactType<MyInheritedWidget>().widget;
}
void updateData(UserInfo info) {_valueNotifier.value = info;}
@override
bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {return false;}
}
次要的变动是:
- 共享数据由 UserInfo 类型变为了 ValueNotifier<UserInfo>。
- 减少了更新数据的办法 updateData。
- updateShouldNotify 办法间接返回了 false,因为数据的更新通过 ValueNotifier 实现。
-
静态方法 of 由
static MyInheritedWidget of(BuildContext context) {return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>(); }
改为
static MyInheritedWidget of(BuildContext context) {return context.getElementForInheritedWidgetOfExactType<MyInheritedWidget>().widget; }
区别是 dependOnInheritedWidgetOfExactType 注册了依赖关系,而 getElementForInheritedWidgetOfExactType 未注册,前面的源码局部会详细分析。
批改 F 组件的代码:
class F extends StatefulWidget {
@override
_FState createState() => _FState();
}
class _FState extends State<F> {
@override
void initState() {super.initState();
print('F initState');
}
@override
void didChangeDependencies() {super.didChangeDependencies();
print('F didChangeDependencies');
}
@override
Widget build(BuildContext context) {print('F build');
return ValueListenableBuilder(builder: (context, UserInfo value, child) {return Text('${value.name}');
},
valueListenable: MyInheritedWidget.of(context).valueNotifier,
);
}
@override
void dispose() {super.dispose();
print('F dispose');
}
}
变动:
- 依赖共享数据的 Text 组件增加了 ValueListenableBuilder 组件,数据发生变化时,从新执行 builder。
_InheritedWidgetDemoState 代码批改如下:
@override
Widget build(BuildContext context) {return MyInheritedWidget(UserInfo(name: '老孟', age: 18), child: Builder(builder: (context) {
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Demo'),
),
body: Center(
child: A(child: F(),
),
),
floatingActionButton: FloatingActionButton(onPressed: () {MyInheritedWidget.of(context)
.updateData(UserInfo(name: '老孟 ${_clickCount++}', age: 18));
},
),
);
},
));
}
运行成果:
重点看 rebuild 的组件,无关的组件(比方 A)没有 rebuild。
当然也能够应用 Provider 实现子组件更新,减少 UserInfoModel:
class UserInfoModel extends ChangeNotifier {UserInfoModel(this._userInfo);
UserInfo _userInfo;
UserInfo get userInfo => _userInfo;
void update(UserInfo userInfo) {
_userInfo = userInfo;
notifyListeners();}
}
批改 _InheritedWidgetDemoState:
class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {
int _clickCount =0;
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserInfoModel(UserInfo(name: '老孟', age: 18))),
],
builder: (context, child) {
return Scaffold(
appBar: AppBar(title: Text('InheritedWidget Demo'),
),
body: Center(
child: A(child: F(),
),
),
floatingActionButton: Consumer<UserInfoModel>(builder: (ctx, userInfoModel, child) {
return FloatingActionButton(
child: child,
onPressed: () {userInfoModel.update(UserInfo(name: '老孟 ${_clickCount++}', age: 18));
},
);
},
),
);
},
);
}
}
InheritedWidget 源码剖析
剖析源码的时候肯定要先想想,如果是我来实现这个组件,要如何实现?InheritedWidget 组件次要实现了两个性能:
- 如何实现绑定依赖它的子组件
- 如何告诉子组件本人产生了更改。
如何实现绑定依赖它的子组件
依赖 InheritedWidget 的子组件如何获取 InheritedWidget 组件的共享数据?首先查看获取共享数据的办法:
context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
这段代码获取 MyInheritedWidget 实例,dependOnInheritedWidgetOfExactType 办法是 BuildContext 的办法,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;
}
从下面的源代码能够看出,首先到 _inheritedWidgets 中查找指定的 InheritedElement,_inheritedWidgets 这个 Map 是哪里来的?什么时候被初始化的?看下 _inheritedWidgets 属性的定义:
Map<Type, InheritedElement> _inheritedWidgets;
查找其援用和赋值的源代码:
@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 中,但此办法在 Element 中也实现了:
void _updateInheritance() {assert(_active);
_inheritedWidgets = _parent?._inheritedWidgets;
}
下面的代码阐明了非 InheritedElement 的 Element 中 _inheritedWidgets 等于父组件的 _inheritedWidgets,而 InheritedElement 会将本身增加到 _inheritedWidgets 中,零碎通过此形式将组件和 InheritedWidgets 的依赖关系层层向下传递,每一个 Element 中都含有 _inheritedWidgets 汇合,此汇合中蕴含了此组件的父组件且是 InheritedWidgets 组件的援用关系。
那么是什么时候执行的 _updateInheritance 办法的呢?通过查找其援用,发现在 mount 和 activate 中调用了 _updateInheritance 办法。对于 mount 和 activate 阶段能够查看 Stateful 组件的生命周期 文章。
上面查看 dependOnInheritedElement 办法,在查找到依赖的 InheritedElement 后,执行 dependOnInheritedElement 办法,源代码如下:
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect}) {assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
updateDependencies 办法源代码如下:
@protected
void updateDependencies(Element dependent, Object aspect) {setDependencies(dependent, null);
}
@protected
void setDependencies(Element dependent, Object value) {_dependents[dependent] = value;
}
下面的代码就是向 _dependents 中增加注册,InheritedWidget 组件更新时能够更具此列表告诉子组件。
再来看下的代码:
@Deprecated(
'Use getElementForInheritedWidgetOfExactType instead.'
'This feature was deprecated after v1.12.1.'
)
@override
InheritedElement ancestorInheritedElementForWidgetOfExactType(Type targetType) {assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
return ancestor;
}
@override
InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
return ancestor;
}
在 v1.12.1 版本以前应用 ancestorInheritedElementForWidgetOfExactType 办法,当初应用 getElementForInheritedWidgetOfExactType 办法,此办法和 dependOnInheritedWidgetOfExactType 办法的惟一却不就是 getElementForInheritedWidgetOfExactType 办法没有注册,也就是应用 getElementForInheritedWidgetOfExactType 办法获取共享数据的子组件,不会在 InheritedWidget 组件重建时调用 didChangeDependencies 办法。
上面看看为什么 InheritedWidget 组件数据形式变动,重建时会调用其 didChangeDependencies 办法?
当组件发生变化时会调用 update办法:
@override
void update(ProxyWidget newWidget) {
final ProxyWidget oldWidget = widget;
assert(widget != null);
assert(widget != newWidget);
super.update(newWidget);
assert(widget == newWidget);
updated(oldWidget);
_dirty = true;
rebuild();}
InheritedElement 重写了 updated 办法:
@override
void updated(InheritedWidget oldWidget) {if (widget.updateShouldNotify(oldWidget))
super.updated(oldWidget);
}
当 updateShouldNotify 返回 true 时,执行更新操作。而其父类的 updated 办法如下:
@protected
void updated(covariant ProxyWidget oldWidget) {notifyClients(oldWidget);
}
notifyClients 办法源代码:
@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);
}
}
遍历 _dependents,下面曾经介绍,_dependents 是依赖它的子组件汇合,遍历调用 notifyDependent 办法:
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {dependent.didChangeDependencies();
}
这里调用了 didChangeDependencies 办法,这也是 InheritedWidget 组件发生变化,重建时执行生命周期 didChangeDependencies。
下面的代码都是在 InheritedElement 中的,在看下 InheritedWidget 的源代码:
abstract class InheritedWidget extends ProxyWidget {const InheritedWidget({ Key key, Widget child})
: super(key: key, child: child);
@override
InheritedElement createElement() => InheritedElement(this);
@protected
bool updateShouldNotify(covariant InheritedWidget oldWidget);
}
这个类非常简单,创立了一个 InheritedElement,定义了一个 updateShouldNotify 办法(下面曾经具体介绍此办法的作用),子类须要重写。
通过下面的源码解析,子组件获取共享数据时,理论是间接在 _inheritedWidgets 汇合中匹配的,通过断点也能够查看其中的内容:
总结
通过下面的剖析,InheritedWidget 组件流程如下:
阐明:
- 在以后组件的 mount 和 activate 阶段,零碎调用 _updateInheritance 办法,将 InheritedWidget 类型的父组件增加到 _inheritedWidgets 汇合中。
- 子组件执行 dependOnInheritedWidgetOfExactType 办法时,从 _inheritedWidgets 汇合中获取指定 InheritedWidget 类型的父组件,并将以后组件注册到 InheritedWidget 类型父组件的 _dependents 汇合中。
- InheritedWidget 组件数据发生变化(updateShouldNotify 办法返回 true),重建时,InheritedWidget 组件遍历 _dependents 汇合中所有依赖的子组件,执行子组件的 didChangeDependencies 的办法。
一点认识
那么为什么是在以后组件的中保留这样一个 Map 汇合,而不是顺次向上查找呢(我最开始的想法)?
上面是我集体的一点认识,如果你有不同的认识,欢送一起探讨:
以后组件的中保留这样一个 Map 汇合,获取共享数据时间接定位依赖的 InheritedWidget,复杂度 O(1)。
而顺次向上查找的复杂度是 O(n),树的构造越深,耗费工夫越长,复杂度线性增长。
交换
老孟 Flutter 博客(330 个控件用法 + 实战入门系列文章):http://laomengit.com
增加微信或者公众号支付《330 个控件大全》和《Flutter 实战》PDF。
欢送退出 Flutter 交换群(微信:laomengit)、关注公众号【老孟 Flutter】: