生命周期的基本概念:
生命周期的本質(zhì)上就是回調(diào)方法,這個(gè)回調(diào)方法能夠讓我們知道這個(gè)widget處于一個(gè)什么樣的狀態(tài)。我們可以實(shí)現(xiàn)這個(gè)方法去監(jiān)聽widget的生命周期。
生命周期的作用:
- 監(jiān)聽widget事件
- 初始化數(shù)據(jù),創(chuàng)建數(shù)據(jù),發(fā)送網(wǎng)絡(luò)請求等等
- 內(nèi)存管理,數(shù)據(jù)銷毀,監(jiān)聽銷毀等等
Widget的生命周期
StatelessWidget
無狀態(tài)的widget比較簡單,StatelessWidget只有一個(gè)build方法和構(gòu)造方法
StatelessWidget會(huì)在底層調(diào)用
StatelessElement createElement() => StatelessElement(this);這個(gè)方法來創(chuàng)建一個(gè)Element樹,在StatelessElement中調(diào)用
Widget build() => widget.build(this);來構(gòu)建widget。
- 構(gòu)造方法
- build方法
代碼驗(yàn)證一下
class LessApp extends StatelessWidget {
final String title;
LessApp({this.title}){
print('構(gòu)造函數(shù)被調(diào)用了');
}
@override
Widget build(BuildContext context) {
print('build被調(diào)用了');
return Center(
child: Text('hello flutter'),
);
}
}
上面運(yùn)行的結(jié)果
StatefulWidget
StatefulWidget包含兩個(gè)對象Widget和State,下面介紹一下它的生命周期
- Widget構(gòu)造方法
- Widget的createState
- State的構(gòu)造方法
- State的initState方法
源碼解釋:Called when this object is inserted into the tree.當(dāng)這個(gè)對象被添加到Widget樹中會(huì)被調(diào)用 - didChangeDependencies方法(依賴關(guān)系改變)
源碼解釋:Called when a dependency of this [State] object changes.當(dāng)該[State]對象的依賴項(xiàng)發(fā)生更改時(shí)調(diào)用。 - State的build方法
我們可以看下源碼,在StatefulWidget源碼里面會(huì)創(chuàng)建一個(gè) Element
StatefulElement createElement() => StatefulElement(this);
StatefulElement里面會(huì)創(chuàng)建一個(gè)狀態(tài)_state,然后會(huì)重寫build方法
Widget build() => _state.build(this);這個(gè)this就是MaterialApp,MaterialApp的Scaffold的body是下面的代碼中的StateApp,這樣就掉用到了該State下的build方法,同時(shí)將widget保存在_state中_state._widget = widget;這也是為什么在state中能夠使用widget來訪問變量,其他的地方則不行的原因。 - didUpdateWidget
這個(gè)一般用在狀態(tài)改變,并且沿著widget傳值使用,比如調(diào)用了setState.
實(shí)際上這里flutter框架會(huì)創(chuàng)建一個(gè)新的Widget,綁定本State,并在這個(gè)函數(shù)中傳遞老的Widget。
這個(gè)函數(shù)一般用于比較新、老Widget,看看哪些屬性改變了 - deactivate
Called when this object is removed from the tree.當(dāng)這個(gè)對象從渲染樹中移除的時(shí)候會(huì)調(diào)用這個(gè)方法。(即將銷毀) - dispose
Called when this object is removed from the tree permanently,當(dāng)對象從渲染樹上已經(jīng)移除調(diào)用該方法。
下面使用示例來詳細(xì)說明,我們設(shè)置了一個(gè)按鈕和一個(gè)text,點(diǎn)擊按鈕text文字會(huì)增量變化。
class StateApp extends StatefulWidget {
final String title;
StateApp({this.title}){
print('構(gòu)造函數(shù)被調(diào)用了');
}
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<StateApp> {
_MyAppState(){
print('State的構(gòu)造方法來了');
}
int _count =0;
@override
void initState() {
print('State的init來了');
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
print('State的build來了');
return Column(
children: <Widget>[
SizedBox(height: 200,),
RaisedButton(
child: Icon(Icons.add),
onPressed: (){
_count++;
setState(() {
});
}
),
Text('$_count'),
],
);
}
@override
void dispose() {
// TODO: implement dispose
print('dispose來了');
super.dispose();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
@override
void deactivate() {
// TODO: implement deactivate
super.deactivate();
}
}
上面這段代碼的運(yùn)行結(jié)果

然后我們點(diǎn)擊按鈕,每次點(diǎn)擊都會(huì)重新調(diào)用build方法改變界面。為什么呢,因?yàn)楫?dāng)我們調(diào)用setState的時(shí)候,追蹤源碼發(fā)現(xiàn)它調(diào)用的是
_element.markNeedsBuild()->rebuild()-> _dirtyElements.add(element)重新加到Element樹中進(jìn)行渲染。
Widget渲染原理
首先flutter中有三棵樹,Widget樹、Element樹、Render樹
- Widget Tree :隱式調(diào)用createElement方法
flutter引擎并不是直接渲染W(wǎng)idget樹,因?yàn)閣idget每一次build都會(huì)重新創(chuàng)建,widget非常不穩(wěn)定,如果直接渲染性能消耗嚴(yán)重,所以widget不是引擎直接渲染的樹。
每一個(gè)Widget都會(huì)創(chuàng)建一個(gè)Element對象,隱式調(diào)用createElement方法,Element加入Element樹中。 - Element Tree有三中RenderElement、StatefulElement、StatelessElement。
RenderElement
主要是創(chuàng)建RenderObject對象
1.創(chuàng)建RanderElement,只要加入Element樹里面就會(huì)執(zhí)行mount方法(createElement執(zhí)行完就會(huì)調(diào)用)
2.Flutter會(huì)調(diào)用mount方法,調(diào)用createRanderObject方法
StatefulElement
StatefulElement繼承ComponentElement
1.調(diào)用createState方法,創(chuàng)建State
2.將Widget賦值給state
3.調(diào)用state的build方法 并且將自己(Element)傳出去,build里面的context 就是Widget的Element。
StatelessElement
StatelessElement繼承ComponentElement
1.StatelessWidget會(huì)創(chuàng)建StatelessElement
2.主要就是調(diào)用build方法 并且將自己(Element)傳出去。
- Render Tree:RenderElement主要是創(chuàng)建RenderObject對象
我們的渲染引擎直接渲染的是Render樹,Render樹放的是RenderObject對象,追蹤源碼可以得知并不是所有的widget都會(huì)加入到Render中,比如我們的StatelessWidget、和StatefulWidget就不是繼承RenderObjectWidget??偨Y(jié):并不是所有的widget都會(huì)被獨(dú)立渲染,只有繼承RenderObjectWidget的才會(huì)創(chuàng)建RenderObject對象,才會(huì)被加入到Render Tree。
總結(jié):上文中我們已經(jīng)知道flutter直接渲染的是Render樹,而widget樹非常不穩(wěn)定,那么就需要一個(gè)橋梁來對比老的widget和新的widget有什么樣的變化,這個(gè)橋梁就是Element樹,創(chuàng)建widget與之對應(yīng)就會(huì)創(chuàng)建一個(gè)一模一樣的Element樹。Element既引用widget樹同時(shí)也通知Render樹哪些是變化的,哪些是沒有變化的,再由渲染引擎來渲染,這樣就大大的提高了效率。