題記
—— 執劍天涯,從你的點滴積累開始,所及之處,必精益求精,即是折騰每一天。
本文将從源碼的角度講述 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 也是肯定不能使用的。
完畢
