-
基本代碼
class Parent extends StatefulWidget {
const Parent({Key? key}) : super(key: key);
@override
State<Parent> createState() {
debugPrint('parent widget----------createState');
return _ParentState();
}
}
class _ParentState extends State<Parent> {
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<Child> createState() {
debugPrint('child widget----------createState');
return _ChildState();
}
}
class _ChildState extends State<Child> {
@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
點(diǎn)擊change
按鈕打印:
flutter: parent state----------build
修改Child
的v
變量的值之后熱更新:
flutter: parent state----------build
flutter: child state----------didUpdateWidget
flutter: child state----------build
修改
Child
在Column
中的順序液样,或者不改變層級使用LocalKey
也會調(diào)用didUpdateWidget
。因?yàn)?code>Widget本身不可變,當(dāng)你修改了Widget
的屬性之后或者直接rebuild
不可避免需要重新創(chuàng)建一個(gè)新的Widget
替換舊的于宙,而同時(shí)舊的State可以復(fù)用,就會調(diào)用State
的didUpdateWidget
悍汛。
-
關(guān)于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'))
],
),
);
}
點(diǎn)擊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
再次點(diǎn)擊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位置變了,由于兩次點(diǎn)擊
ChildState
的層級不同离咐,優(yōu)先處理更深層次谱俭,再處理父層。
盡管有
Key
宵蛀,但是由于層級改變了昆著,所有不會復(fù)用State
-
關(guān)于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,
)
],
),
);
}
點(diǎn)擊change
按鈕,打印如下:
flutter: parent state----------build
flutter: child state----------deactivate
flutter: child state----------activate
flutter: child state----------didUpdateWidget
flutter: child state----------build
這里可以看到
activate
的打印术陶,因?yàn)槭褂昧?code>GlobalKey凑懂,且改變了Child
的層級,其State
在rebuild
過程中從樹中移除后又重新插入新的位置梧宫。
-
關(guān)于didChangeDependencies
可以看到初始化渲染調(diào)用了
child-didChangeDependencies
接谨,這是因?yàn)樽铋_始child并不存在摆碉,在parent
動(dòng)用updateChild
的時(shí)候不存在舊的child
,那么會直接調(diào)用inflateWidget
->mount
->_firstBuild
->didChangeDependencies
疤坝。在
inflateWidget
中兆解,會判斷‘GlobalKey’,即能不能在inactiveElement
之中找到可用的Element
跑揉,如果找到了就不用重新創(chuàng)建新的Element
锅睛,也就不會調(diào)用didChangeDependencies
。如果沒找到可用的
Element
历谍,就會創(chuàng)建新的Element
现拒,這個(gè)時(shí)候就會調(diào)用mount
方法,將新的Element
插入樹中望侈,注意由于Element.mount
不調(diào)用_firstBuild
印蔬,只有ComponentElement
他重寫了mount
,其中調(diào)用了_firstBuild
脱衙。之所以會調(diào)用ComponentElement.mount
是因?yàn)?code>StatefulElement繼承自ComponentElement
侥猬,而我們demo中的Child
是StatefulWidget
,對應(yīng)的Element
就是StatefulElement
捐韩。在大部分情況下退唠,調(diào)用
didChangeDependencies
的時(shí)候都會調(diào)用initState
,那么在什么時(shí)候才只會調(diào)用didChangeDependencies
荤胁?在使用InheritedWidget
的時(shí)候瞧预,代碼如下:
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<ShareDataWidget>();
}
@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(),
)
],
),
);
}
這個(gè)時(shí)候點(diǎn)擊change
按鈕打印如下:
flutter: parent state----------build
flutter: child state----------didChangeDependencies
flutter: child state----------build
當(dāng)ShareDataWidget只是一個(gè)普通Widget
的時(shí)候,打咏稣:
flutter: parent state----------build
這里已經(jīng)很清晰了垢油,
Parent
每次build
其實(shí)是重新運(yùn)行了build
函數(shù)內(nèi)的代碼,那么其中的Widget
必定會改變圆丹,而對應(yīng)的Element
和State
則盡量不改變滩愁。那么如果沒有特殊的變化,單純rebuild
是不會觸發(fā)除build
之外的任何生命周期函數(shù)运褪。而如果使用了InheritedWidget
惊楼,那么當(dāng)其攜帶的信息改變時(shí)就有必要通知依賴
它的State
,這里就是通過didChangeDependencies
告知這種變化秸讹。