-
基本代码
class Parent extends StatefulWidget {
const Parent({Key? key}) : super(key: key);
@override
State createState() {
debugPrint('parent widget----------createState');
return _ParentState();
}
}
class _ParentState extends State {
bool inContainer = false;
@override
void initState() {
debugPrint('parent state----------initState');
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
debugPrint('parent state----------addPostFrameCallback');
});
}
@override
void didChangeDependencies() {
debugPrint('parent state----------didChangeDependencies');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
debugPrint('parent state----------build');
return Scaffold(
appBar: AppBar(
title: const Text('one child'),
),
body: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
inContainer = !inContainer;
});
},
child: const Text('change'),
),
const Child()
],
),
);
}
@override
void didUpdateWidget(covariant Parent oldWidget) {
debugPrint('parent state----------didUpdateWidget');
super.didUpdateWidget(oldWidget);
}
@override
void activate() {
debugPrint('parent state----------activate');
super.activate();
}
@override
void deactivate() {
debugPrint('parent state----------deactivate');
super.deactivate();
}
@override
void dispose() {
debugPrint('parent state----------dispose');
super.dispose();
}
}
class Child extends StatefulWidget {
final v = 1;
const Child({Key? key}) : super(key: key);
@override
State createState() {
debugPrint('child widget----------createState');
return _ChildState();
}
}
class _ChildState extends State {
@override
void initState() {
debugPrint('child state----------initState');
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
debugPrint('child state----------addPostFrameCallback');
});
}
@override
void didChangeDependencies() {
debugPrint('child state----------didChangeDependencies');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
debugPrint('child state----------build');
return const Text('cus-widget');
}
@override
void didUpdateWidget(covariant Child oldWidget) {
debugPrint('child state----------didUpdateWidget');
super.didUpdateWidget(oldWidget);
}
@override
void activate() {
debugPrint('child state----------activate');
super.activate();
}
@override
void deactivate() {
debugPrint('child state----------deactivate');
super.deactivate();
}
@override
void dispose() {
debugPrint('child state----------dispose');
super.dispose();
}
}
初始渲染后的打印:
flutter: parent widget----------createState
flutter: parent state----------initState
flutter: parent state----------didChangeDependencies
flutter: parent state----------build
flutter: child widget----------createState
flutter: child state----------initState
flutter: child state----------didChangeDependencies
flutter: child state----------build
flutter: parent state----------addPostFrameCallback
flutter: child state----------addPostFrameCallback
点击change
按钮打印:
flutter: parent state----------build
修改Child
的v
变量的值之后热更新:
flutter: parent state----------build
flutter: child state----------didUpdateWidget
flutter: child state----------build
修改
Child
在Column
中的顺序,或者不改变层级使用LocalKey
也会调用didUpdateWidget
。因为Widget
本身不可变,当你修改了Widget
的属性之后或者直接rebuild
不可避免需要重新创建一个新的Widget
替换旧的,而同时旧的State可以复用,就会调用State
的didUpdateWidget
。
-
关于deactivate
将Parent
的build
方法修改如下:
Widget build(BuildContext context) {
debugPrint('parent state----------build');
return Scaffold(
appBar: AppBar(
title: const Text('one child'),
),
body: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
inContainer = !inContainer;
});
},
child: const Text('change'),
),
inContainer
? Container(
color: Colors.blue,
child: const Child(key: ValueKey('123')),
)
: const Child(key: ValueKey('123'))
],
),
);
}
点击change
按钮
flutter: parent state----------build
flutter: child widget----------createState
flutter: child state----------initState
flutter: child state----------didChangeDependencies
flutter: child state----------build
flutter: child state----------deactivate
flutter: child state----------dispose
flutter: child state----------addPostFrameCallback
再次点击change
按钮
flutter: parent state----------build
flutter: child state----------deactivate
flutter: child widget----------createState
flutter: child state----------initState
flutter: child state----------didChangeDependencies
flutter: child state----------build
flutter: child state----------dispose
flutter: child state----------addPostFrameCallback
需要注意,两次打印deactivate位置变了,由于两次点击
ChildState
的层级不同,优先处理更深层次,再处理父层。
尽管有
Key
,但是由于层级改变了,所有不会复用State
-
关于activate
将Child
的build
修改如下:
final GlobalKey _gk = GlobalKey();
@override
Widget build(BuildContext context) {
debugPrint('parent state----------build');
return Scaffold(
appBar: AppBar(
title: const Text('one child'),
),
body: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
inContainer = !inContainer;
});
},
child: const Text('change'),
),
inContainer
? Container(
color: Colors.blue,
child: Child(key: _gk),
)
: Child(
key: _gk,
)
],
),
);
}
点击change
按钮,打印如下:
flutter: parent state----------build
flutter: child state----------deactivate
flutter: child state----------activate
flutter: child state----------didUpdateWidget
flutter: child state----------build
这里可以看到
activate
的打印,因为使用了GlobalKey
,且改变了Child
的层级,其State
在rebuild
过程中从树中移除后又重新插入新的位置。
-
关于didChangeDependencies
可以看到初始化渲染调用了
child-didChangeDependencies
,这是因为最开始child并不存在,在parent
动用updateChild
的时候不存在旧的child
,那么会直接调用inflateWidget
->mount
->_firstBuild
->didChangeDependencies
。在
inflateWidget
中,会判断‘GlobalKey’,即能不能在inactiveElement
之中找到可用的Element
,如果找到了就不用重新创建新的Element
,也就不会调用didChangeDependencies
。如果没找到可用的
Element
,就会创建新的Element
,这个时候就会调用mount
方法,将新的Element
插入树中,注意由于Element.mount
不调用_firstBuild
,只有ComponentElement
他重写了mount
,其中调用了_firstBuild
。之所以会调用ComponentElement.mount
是因为StatefulElement
继承自ComponentElement
,而我们demo中的Child
是StatefulWidget
,对应的Element
就是StatefulElement
。在大部分情况下,调用
didChangeDependencies
的时候都会调用initState
,那么在什么时候才只会调用didChangeDependencies
?在使用InheritedWidget
的时候,代码如下:
class ShareDataWidget extends InheritedWidget {
final int data;
const ShareDataWidget(
this.data, {
Key? key,
required Widget child,
}) : super(key: key, child: child);
static ShareDataWidget? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
@override
bool updateShouldNotify(covariant ShareDataWidget oldWidget) {
return oldWidget.data != data;
}
}
将Parent
的build
修改如下:
@override
Widget build(BuildContext context) {
debugPrint('parent state----------build');
return Scaffold(
appBar: AppBar(
title: const Text('one child'),
),
body: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
inContainer = !inContainer;
});
},
child: const Text('change'),
),
ShareDataWidget(
inContainer ? 1 : 2,
child: const Child(),
)
],
),
);
}
这个时候点击change
按钮打印如下:
flutter: parent state----------build
flutter: child state----------didChangeDependencies
flutter: child state----------build
当ShareDataWidget只是一个普通Widget
的时候,打印:
flutter: parent state----------build
这里已经很清晰了,
Parent
每次build
其实是重新运行了build
函数内的代码,那么其中的Widget
必定会改变,而对应的Element
和State
则尽量不改变。那么如果没有特殊的变化,单纯rebuild
是不会触发除build
之外的任何生命周期函数。而如果使用了InheritedWidget
,那么当其携带的信息改变时就有必要通知依赖
它的State
,这里就是通过didChangeDependencies
告知这种变化。