寫了這么多,無非就是State文檔貼過來,最有感觸的就兩點:
- State 的生命周期和 StatefulWidget 不同,當 StatefulWidget 狀態改變后就會被重建,但是 State 不會改變,但是當 StatefulWidget 在 View 樹中移除再插入又會生成新的 State。參考下文 State.context.
- initState -> build -> 狀態改變 -> didUpdateWidget -> build --->移除.
在學習 flutter 的時候,總會用到 StatefulWidget,它是一個有狀態的 widget,會根據不同狀態有不同顯示,它的生命周期與 State 有關,它的基本寫法如下
// flutter官方教程里面的一個類,點擊一個關注的星星,然后就表明已經關注。再點擊表示不再關注,默認狀態是已關注,關注數是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 樹中的時候,每當調用 States.setState() 時,都會重新build一次FavoriteWidget ,然后將新的 Views代替原先的,并顯示給用戶。
您可能想知道為什么 StatefulWidget 和 State 是單獨的對象。在 Flutter 中,這兩種類型的對象具有不同的生命周期: Widget 是臨時對象,用于構建當前狀態下的應用程序,而 State 對象在多次調用
build()
之間保持不變,允許它們記住信息(狀態)。
那么首先得知道,State的生命周期是什么?
一、生命周期
突然看到這個圖,可能會有點懵,因為許多方法都不清是干什么的,稍后會慢慢講解,不耐煩的可以跳到最后每個方法的總結,這里先總體介紹一下生命周期,大致可以看成三個階段:
- 初始化(插入渲染樹)
- 狀態改變(在渲染樹中存在)
- 銷毀(從渲染樹種移除)
先舉 FavoriteWidget
為例,當這個 Widget 首次插入到樹中時,框架會調用其 createState
函數以創建一個新的_FavoriteWidgetState
實例來與該樹中的相應位置關聯(請注意,我們通常命名State子類時帶一個下劃線,這表示其是私有的)。 當這個widget的父級重建時,父級將創建一個新的FavoriteWidget
實例,但是Flutter框架將重用已經在樹中的_FavoriteWidgetState
實例,而不是再次調用createState
創建一個新的。
從 StatefulWidget 調用createState之后,框架將新的狀態對象插入樹中,然后調用 State 的initState
,接著如上圖所示走了一遍自身的生命周期。需要注意的是,StatefulWidget 和 State 是不同的生命周期。
二、State 源文檔翻譯
State 是當 Widget 被渲染或者在其生命周期中狀態改變時,能同步讀到相關信息的對象。當實例StatefulWidget 時(下文說的 Widget 無特別說明,都是StatefulWidget 懶得打),必須保證能正確使用 State.setState 來告知該 Widget的狀態發生了變化。
當渲染這個 Widget 并將其插入View 樹中,會調用 StatefulWidget.createState 然后,framework 就會創建一個 State 對象。 因為一個 Widget 可以被 inflated 多次,比如說 這個 FavoriteWidget 可以被多個地方用到,所以這里會存在多個 _FavoriteWidgetState 與之綁定。同樣,當 Widget 被移除出 Views 樹的時候,然后又重新插入,這時候 framework 會再次調用StatefulWidget.createState 來創建一個新的 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 當前是否正確綁定在View樹中。當創建 State 對象,并在調用 State.initState 之前,framework 會根據 BuildContext 來標記 mounted,然后在 State的生命周期里面,這個 mounted 屬性不會改變,直至 framework 調用 State.dispose,當改變之后, State 對象再也不會調用 build 方法,而且當 mounted = false 時,調用 State.setState 會報錯。
- The framework calls initState. 在State 生命周期中只會調用一次。
- The framework calls didChangeDependencies. 一般是在初始化中調用,但是如果BuildContext.inheritFromWidgetOfExactType 被調用,那么當widgets 改變或者是在 Views 樹中移動,didChangeDependencies將會再一次調用。
- 當 State 完全初始化后,framework 會多次調用 build來獲取綁定的實例化 Widget 的信息。同時,當調用 setState 方法時,State 會自發的重建 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
flutter
tool 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 推舉