Flutter - State類

寫了這么多,無非就是State文檔貼過來,最有感觸的就兩點:

  1. State 的生命周期和 StatefulWidget 不同,當 StatefulWidget 狀態改變后就會被重建,但是 State 不會改變,但是當 StatefulWidget 在 View 樹中移除再插入又會生成新的 State。參考下文 State.context.
  2. 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的生命周期是什么?

一、生命周期

轉載自jzoom_flutter中的生命周期.png

突然看到這個圖,可能會有點懵,因為許多方法都不清是干什么的,稍后會慢慢講解,不耐煩的可以跳到最后每個方法的總結,這里先總體介紹一下生命周期,大致可以看成三個階段:

  • 初始化(插入渲染樹)
  • 狀態改變(在渲染樹中存在)
  • 銷毀(從渲染樹種移除)

先舉 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 pressing r, 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 推舉

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374