flutter如何創建的視圖樹(WidgetTree),元素樹(ElementTree)及渲染樹(RenderingTree),又是如何更新視圖繪製視圖? 這個問題太大,剛開始一切又都是陌生的,理解起來千頭萬緒,因此先搞清這些樹的根結點的身份是很是必要的。毫無疑問,這些根節點的創建緊密的與初始化過程關聯,而肯定了這些根節點以後,遍歷查找更新就相對清晰了,由於繪製視圖無非也是對樹的遍歷查找更新操做。java
這部分就已經從引擎層進入到了dart層,須要瞭解的更多的是框架相關的機制,引擎目前用不到了。git
環境: flutter sdk v1.7.8+hotfix.4@stablegithub
先不要被Element
, RenderObjectElement
, RenderObject
, Widget
,RenderObjectWidget
諸多名稱嚇到。與安卓封裝了顯式的啓動運行過程不一樣,flutter有一個明確的runApp
, 這就是進行分析的方便入口。bash
須要先了解一下語言層面的一個多繼承機制。雖然這裏用了多繼承這個名詞,可是須要明確dart語言在語法上仍是單繼承,也就是隻能extends
一個類,其它接口分別再以with
串接。框架
與java不一樣,dart沒有interface
(準確的說是已移除)只有abstract
,abstract
的使用與java並沒有二致。沒有了interface
如何實現多接口對象的聲明?dart用的是mixin
關鍵字,因此就方便理解而言,把mixin
看成interface
, on
看成extends
(只針對mixin
類)便可。與interface
不一樣的是**mixin
聲明的類是能夠有方法實現體和成員對象的**。ide
class A extends B implements C, D, E {}
class B {}
interface C {}
interface D {}
interface E {}
複製代碼
dart等同於:函數
class A extends B with C, D, E {}
class B {}
mixin C {}
mixin D {}
mixin E {}
複製代碼
在以上例子中假如B,C,D都有doSomeThing
方法post
class A extends B with C, D {
@override
void doSomeThing() {
print("A");
super.doSomeThing();
}
}
class B {
@override
void doSomeThing() {
print("B");
}
}
mixin C on B {
@override
void doSomeThing() {
print("C");
super.doSomeThing();
}
}
mixin D on B {
@override
void doSomeThing() {
print("D");
super.doSomeThing();
}
}
void main() {
A().doSomeThing();
}
複製代碼
那麼當執行A.doSomeThing
後應該是哪一個調用順序? 直接給結論:以with聲明的反順序繼承 那麼問題來了:若是沒有C on B
會發生什麼? 語言機制問題可參考這篇文章。ui
須要瞭解的第2個語法特性是串連調用,能夠用..
操做符串連調用類的成員方法:this
class F {
String str;
String contact(String s) {
return str + s;
}
void assign(String s) {
str = s;
}
}
void mai() {
F f = F()..assign("hello")..contact(' world');
print(f.str);
}
複製代碼
須要明確:用了..
操做符以後調用返回的就是類對象實例,再也不是方法的返回值。
有了以上基礎(用到語言特性1: mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding
)就能夠理清runApp
入口的調用序列:
runApp
WidgetsFlutterBinding.ensureInitialized
WidgetsFlutterBinding()
BindingBase()
WidgetsBinding.initInstances
RendererBinding.initInstances
SemanticsBinding.initInstances
PaintingBinding.initInstances
SchedulerBinding.initInstances
ServicesBinding.initInstances
GestureBinding.initInstances
BindingBase.initInstances
複製代碼
這裏包含了大量的數據初始化,用到一個找一個。 再看總體序列(widgets/binding.dart:786, 用到語言特性2):
runApp
WidgetsFlutterBinding.ensureInitialized
WidgetsBinding.attachRootWidget
WidgetsBinding.scheduleWarmUpFrame
複製代碼
MyApp
實例被傳給了WidgetsBinding.attachRootWidget
方法,因而分析其調用序列:
runApp
WidgetsBinding.attachRootWidget
RenderObjectToWidgetAdapter()
RenderObjectToWidgetAdapter.attachToRenderTree
RenderObjectToWidgetAdapter.createElement
RenderObjectToWidgetElement<RenderBox>.assignOwner
BuildOwner.buildScope
RenderObjectToWidgetElement<RenderBox>.mount
複製代碼
須要注意RenderObjectToWidgetAdapter
是一個RenderObjectWidget
類型,它用構造函數child: rootWidget,
持有了外部傳入的rootWidget
做爲它的子視圖。 RenderObjectToWidgetAdapter.createElement
建立的元素被賦值給了_renderViewElement
,_renderViewElement
被WidgetsBinding
實例持有。
那根渲染又是什麼時候建立的呢?繼續看mount
的調用序列:
RenderObjectToWidgetElement<RenderBox>.mount
RootRenderObjectElement.mount
RenderObjectElement.mount
RenderObjectWidget.createRenderObject => RenderObjectToWidgetAdapter.createRenderObject
複製代碼
這裏容易讓人誤導,調用createRenderObject
的實際上是RenderObjectElement
持有的RenderObjectWidget
, 而元素RenderObjectToWidgetElement
正是RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this)
(widgets/binding.dart:833)所建立,這裏的this
其實就是RenderObjectToWidgetAdapter
,因此根渲染是RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;
(widgets/bindings.836),可見根渲染不是在此時建立的,而是預先被賦值僅在此時返回的。
因而可知MyApp
做爲外部傳入的rootWidget
不是真正的根視圖,真正的根視圖實際上是RenderObjectToWidgetAdapter
, 它被RenderObjectToWidgetElement<RenderBox>
持有(一個Element持有一個Widget), 而這個Element被全局WidgetsBinding
實例持有,因此根元素爲RenderObjectToWidgetElement<RenderBox>
。
RenderObjectElement
在mount
的時機建立了一個RenderObject
實例並持有,而RenderObjectToWidgetElement
是RenderObjectElement
的子類,建立的RenderObject
具體類型爲RenderObjectWithChildMixin<RenderBox>
,因此它纔是最終的根渲染。
有了rootElement
就能夠找到rootWidget
和rootRenderObject
, 元素樹,視圖樹與渲染樹由此創建起來。
回到RenderObjectToWidgetAdapter
調用構造函數的地方,傳入的container
是RenderingBinding
的RenderView get renderView => _pipelineOwner.rootNode;
(rendering/binding.dart:162, attachRootWidget
是WidgetsBinding
的方法,但 mixin WidgetsBinding on RendererBinding
,因此能夠引用到RenderingBinding
的成員)。
那麼rootRenderObject,也就是上面的RenderView
, 做爲RenderObjectWithChildMixin<RenderBox>
的子類(class RenderView with RenderObjectWithChildMixin<RenderBox>
),又是在什麼時機建立的?跟蹤下來正是在初始化調用中:
runApp
WidgetsFlutterBinding.ensureInitialized
WidgetsFlutterBinding()
BindingBase()
WidgetsBinding.initInstances
RendererBinding.initInstances
_pipelineOwner = PipelineOwner(
RendererBinding.initRenderView
renderView = RenderView()
_pipelineOwner.rootNode = value;
複製代碼
也就是說WidgetBinding把RendererBinding(mixin WidgetBinding with RendererBinding
)的renderView
做爲了根渲染,而它實際是_pipelineOwner.rootNode
。
至此,咱們便知道了全部節點遍歷的起點。