天天看點

Flutter中State深入分析了解

題記

—— 執劍天涯,從你的點滴積累開始,所及之處,必精益求精,即是折騰每一天。

本文将從源碼的角度講述 State 的 四種狀态 的變換時機,以及 從 State 的角度來了解 BuildContext 的使用時機

State 有四種狀态:

  • created:當State對象被建立時候,State.initState方法會被調用;
  • initialized:當State對象被建立,但還沒有準備建構時,State.didChangeDependencies在這個時候會被調用;
  • ready:State對象已經準備好了建構,State.dispose沒有被調用的時候;
  • defunct:State.dispose被調用後,State對象不能夠被建構。

當一個 Widget 被挂載到 Widgets 樹上時,目前的StatefulWidget中通過Widget.createElement方法來建立Element,然後架構層會調用RenderObjectWidget.createRenderObject()來執行個體化RenderObject,然後Element(就是我們說的BuildContext)關聯 Widget 與 RenderObject,這個在

Flutter中Widget 、Element、RenderObject角色深入分析

一節中有描述。

在這裡 Element 與Widget 是通過 State來關聯的,在 Widget 被挂載到 Widgets 樹上時,會通過 StatefulWidget 的createElement 方法來建立一個StatefulElement,源碼如下:

///代碼清單 1-1 
///StatefulWidget 源碼 
abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ Key key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  State createState();
}           

然後在對應的StatefulElement 中 通過 widget 的 createState 方法來建立一個State,源碼如下代碼清單 1-2所示 ,在 StatefulElement 使用到的 widget 就是在代碼清單 1-1 中所對應的

StatefulWidget。

///代碼清單 1-2 
class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
        ... ... 
}           

然後此時 State 的狀态為 create 狀态 ,需要注意的是此時 是在 StatefulElement 的構造函數中執行的,之後會在 StatefulElement 的 _firstBuild 方法中回調 initState方法,而此時State 的狀态依然為 create 狀态,是以 State是不可用狀态,對應的 StatefulElement的(BuildContext)也是不可用狀态。

對于 mounted 這個屬性,在framework中是直接根據 判斷目前 Widget 對應的 Element 是否為空來取值 的,如下所示:

bool get mounted => _element != null;           

StatefulElement 的建立 是在 回調 initState方法 之前,如下代碼清單1-3 中所示,StatefulElement 繼承于 ComponentElement,在父類 ComponentElement的構造函數中給 變量 _element 指派, 是以在 實際開發中,在 Widget 的 initState 方法中 擷取的 mounted 值為 true , State 對應的狀态 為 create , Widget 與 Element 通過 State 挂載 , Element 還不可使用,也就是 context 還不可使用。

///代碼清單
class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
     ...
    _state._element = this;
    ...
  }
           

之後 State 的狀态 更新 為 initialized 狀态,然後回調 didChangeDependencies , initialized 狀态 Element 已經将 Widget 與對應 的 RenderObject 關聯好, 通過Element 可以擷取 RenderObject 中進行測量與計算的一些基本資訊,也就是 此時就可以使用 Element (BuildContext)。

initialized 狀态 是 Element 在 Widget 與對應 的 RenderObject 形成綁定關系後,還沒有裡德繪制(build)前的狀态,是已準備好的狀态 。

之後 State 的狀态 更新 為 ready 狀态 ,目前(StatefulElement)回調父類(ComponentElement)的 _firstBuild 方法 ,在 ComponentElement 的 _firstBuild 方法中

rebuild ->performRebuild ,對應的RenderObject會被 插到對應的 render樹上,然後繪制顯示出來。

當 Widget 被 移除時 ,通過 Navigator 的 pop 或者 是在具體的 build 方法中通過變量控制将一個已在頁面上渲染顯示出來的Widget 移除不顯示時,這個 Widget 對應的狀态 變為defunct,不可用狀态,同時 對應的 Element 與 Widget 、RenderObject 也會解綁,在解綁前會回調這個 Widget 的 didChangeDependencies 方法 ,此時 mounted 值為 true ,因為 對應的 Element 隻是準備解綁,還不為null。

當解綁後 回調 dispose ,此時對應的 Element 已被 移除,為null ,是以 此時 被移除的 Widget中的 mounted 值為 false, 當然在這裡 context 也是肯定不能使用的。

完畢

Flutter中State深入分析了解

繼續閱讀