寫了這么多,無非就是State文檔貼過來,最有感觸的就兩點:
- State 的生命周期和 StatefulWidget 不同,當(dāng) StatefulWidget 狀態(tài)改變后就會被重建,但是 State 不會改變,但是當(dāng) StatefulWidget 在 View 樹中移除再插入又會生成新的 State。參考下文 State.context.
- initState -> build -> 狀態(tài)改變 -> didUpdateWidget -> build --->移除.
在學(xué)習(xí) flutter 的時候,總會用到 StatefulWidget,它是一個有狀態(tài)的 widget,會根據(jù)不同狀態(tài)有不同顯示,它的生命周期與 State 有關(guān),它的基本寫法如下
// flutter官方教程里面的一個類,點擊一個關(guān)注的星星,然后就表明已經(jīng)關(guān)注。再點擊表示不再關(guān)注,默認狀態(tài)是已關(guān)注,關(guān)注數(shù)是41
class FavoriteWidget extends StatefulWidget {
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State<FavoriteWidget> {
bool _isFavorited = true;
int _favoriteCount = 41;
void _toggleFavorite() {
setState(() {
// If the lake is currently favorited, unfavorite it. Otherwise, favorite it.
_favoriteCount = _isFavorited?_favoriteCount -1:_favoriteCount +1 ;
_isFavorited = !_isFavorited;
});
}
@override
Widget build(BuildContext context) {
return new Widget(
// build by states
);
}
}
將 FavoriteWidget 插入到 Views 樹中的時候,每當(dāng)調(diào)用 States.setState() 時,都會重新build一次FavoriteWidget ,然后將新的 Views代替原先的,并顯示給用戶。
您可能想知道為什么 StatefulWidget 和 State 是單獨的對象。在 Flutter 中,這兩種類型的對象具有不同的生命周期: Widget 是臨時對象,用于構(gòu)建當(dāng)前狀態(tài)下的應(yīng)用程序,而 State 對象在多次調(diào)用
build()之間保持不變,允許它們記住信息(狀態(tài))。
那么首先得知道,State的生命周期是什么?
一、生命周期

突然看到這個圖,可能會有點懵,因為許多方法都不清是干什么的,稍后會慢慢講解,不耐煩的可以跳到最后每個方法的總結(jié),這里先總體介紹一下生命周期,大致可以看成三個階段:
- 初始化(插入渲染樹)
- 狀態(tài)改變(在渲染樹中存在)
- 銷毀(從渲染樹種移除)
先舉 FavoriteWidget 為例,當(dāng)這個 Widget 首次插入到樹中時,框架會調(diào)用其 createState 函數(shù)以創(chuàng)建一個新的_FavoriteWidgetState實例來與該樹中的相應(yīng)位置關(guān)聯(lián)(請注意,我們通常命名State子類時帶一個下劃線,這表示其是私有的)。 當(dāng)這個widget的父級重建時,父級將創(chuàng)建一個新的FavoriteWidget實例,但是Flutter框架將重用已經(jīng)在樹中的_FavoriteWidgetState實例,而不是再次調(diào)用createState創(chuàng)建一個新的。
從 StatefulWidget 調(diào)用createState之后,框架將新的狀態(tài)對象插入樹中,然后調(diào)用 State 的initState,接著如上圖所示走了一遍自身的生命周期。需要注意的是,StatefulWidget 和 State 是不同的生命周期。
二、State 源文檔翻譯
State 是當(dāng) Widget 被渲染或者在其生命周期中狀態(tài)改變時,能同步讀到相關(guān)信息的對象。當(dāng)實例StatefulWidget 時(下文說的 Widget 無特別說明,都是StatefulWidget 懶得打),必須保證能正確使用 State.setState 來告知該 Widget的狀態(tài)發(fā)生了變化。
當(dāng)渲染這個 Widget 并將其插入View 樹中,會調(diào)用 StatefulWidget.createState 然后,framework 就會創(chuàng)建一個 State 對象。 因為一個 Widget 可以被 inflated 多次,比如說 這個 FavoriteWidget 可以被多個地方用到,所以這里會存在多個 _FavoriteWidgetState 與之綁定。同樣,當(dāng) Widget 被移除出 Views 樹的時候,然后又重新插入,這時候 framework 會再次調(diào)用StatefulWidget.createState 來創(chuàng)建一個新的 State 對象。
State 的生命周期如下:
- The framework creates a State object by calling StatefulWidget.createState.
- 這個新的 State 對象將會綁定一個 BuildContext ,這個綁定是永久的。 State 永遠也不會改變其 BuildContext (所以它的屬性中,contenxt是只讀的??梢园堰@個理解成 Widget 在 Views 樹中的位置,文檔中是 The location in the tree where this widget builds.)但是, BuildContext 自身卻是可以改變的,可以因為 Widget 在樹中的位置變化而變化。由此,State 有一個屬性是 mounted 表明 State 當(dāng)前是否正確綁定在View樹中。當(dāng)創(chuàng)建 State 對象,并在調(diào)用 State.initState 之前,framework 會根據(jù) BuildContext 來標(biāo)記 mounted,然后在 State的生命周期里面,這個 mounted 屬性不會改變,直至 framework 調(diào)用 State.dispose,當(dāng)改變之后, State 對象再也不會調(diào)用 build 方法,而且當(dāng) mounted = false 時,調(diào)用 State.setState 會報錯。
- The framework calls initState. 在State 生命周期中只會調(diào)用一次。
- The framework calls didChangeDependencies. 一般是在初始化中調(diào)用,但是如果BuildContext.inheritFromWidgetOfExactType 被調(diào)用,那么當(dāng)widgets 改變或者是在 Views 樹中移動,didChangeDependencies將會再一次調(diào)用。
- 當(dāng) State 完全初始化后,framework 會多次調(diào)用 build來獲取綁定的實例化 Widget 的信息。同時,當(dāng)調(diào)用 setState 方法時,State 會自發(fā)的重建 Widget 的子 Views。
- During this time, a parent widget might rebuild and request that this location in the tree update to display a new widget with the same runtimeType and Widget.key.When this happens, the framework will update the widget property to refer to the new widget and then call the didUpdateWidget method with the previous widget as an argument. State objects should override didUpdateWidget to respond to changes in their associated widget (e.g., to start implicit animations). The framework always calls build after calling didUpdateWidget, which means any calls to setState in didUpdateWidget are redundant.
- During development, if a hot reload occurs (whether initiated from the command line
fluttertool by pressingr, or from an IDE), the reassemble method is called. This provides an opportunity to reinitialize any data that was prepared in the initState method. - f the subtree containing the State object is removed from the tree (e.g., because the parent built a widget with a different runtimeType or Widget.key), the framework calls the deactivate method. Subclasses should override this method to clean up any links between this object and other elements in the tree (e.g. if you have provided an ancestor with a pointer to a descendant's RenderObject).
- At this point, the framework might reinsert this subtree into another part of the tree. If that happens, the framework will ensure that it calls build to give the State object a chance to adapt to its new location in the tree. If the framework does reinsert this subtree, it will do so before the end of the animation frame in which the subtree was removed from the tree. For this reason, State objects can defer releasing most resources until the framework calls their dispose method.
- If the framework does not reinsert this subtree by the end of the current animation frame, the framework will call dispose, which indicates that this State object will never build again. Subclasses should override this method to release any resources retained by this object (e.g., stop any active animations).
- After the framework calls dispose, the State object is considered unmounted and the mountedproperty is false. It is an error to call setState at this point. This stage of the lifecycle is terminal: there is no way to remount a State object that has been disposed.
| 名稱 | 返回值/類型 | 意義 |
|---|---|---|
| context read-only | BuildContext | The location in the tree where this widget builds. |
| mounted read-only | bool | Whether this State object is currently in a tree. |
| widget read-only | T | The current configuration. |
| hashCode read-only, inherited | int | The hash code for this object. |
| runtimeType read-only, inherited | Type | A representation of the runtime type of the object. |
| build(BuildContext context) | Widget | Describes the part of the user interface represented by this widget. |
| deactivate() | void | Called when this object is removed from the tree. |
| debugFillProperties(DiagnosticPropertiesBuilder properties) | void | Add additional properties associated with the node. |
| didChangeDependencies() | void | Called when a dependency of this State object changes. |
| didUpdateWidget(T oldWidget) | void | Called whenever the widget configuration changes. |
| dispose() | void | Called when this object is removed from the tree permanently. |
| initState() | void | Called when this object is inserted into the tree. |
| reassemble() | void | Called whenever the application is reassembled during debugging, for example during hot reload. |
| setState (VoidCallback fn) | void | Notify the framework that the internal state of this object has changed. |
參考資料:
https://docs.flutter.io/flutter/widgets/State-class.html
https://segmentfault.com/a/1190000015211309 推舉