說起啟動那必須從main方法開始呀
void main() => runApp(MyApp());
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
runApp的代碼很簡單遮晚,傳遞一個Widget參數腊徙,然后執(zhí)行了三行代碼惨寿,三行代碼代表了Flutter App啟動的主要三個流程:
- binding初始化(ensureInitialized)
- 綁定根節(jié)點(scheduleAttachRootWidget)
- 繪制熱身幀(scheduleWarmUpFrame)
binding初始化(ensureInitialized)
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
mixin我們前面已經介紹過了,不難發(fā)現 WidgetsFlutterBinding 單例過程其實也是對7個mixin的binding的初始化 和橙。
WidgetsFlutterBinding繼承了BindingBase,在調用自己的構造器之前會先先執(zhí)行了父類BindingBase構造函數舟误。
BindingBase() {
developer.Timeline.startSync('Framework initialization');
assert(!_debugInitialized);
initInstances();
assert(_debugInitialized);
assert(!_debugServiceExtensionsRegistered);
initServiceExtensions();
assert(_debugServiceExtensionsRegistered);
developer.postEvent('Flutter.FrameworkInitialization', <String, String>{});
developer.Timeline.finishSync();
}
WidgetsBinding 覆蓋了前面的 binding 的 initInstances()葡秒,所以 WidgetsBinding 的 initInstances() 會首先被調用,而 WidgetsBinding 的 initInstances 函數中先通過 super 向上調用 initInstances ,根據mixin的特性 執(zhí)行順序: initInstances 的執(zhí)行順序依次是:BindingBase -> GestureBinding -> SchedulerBinding -> ServicesBinding -> PaintingBinding -> SemanticsBinding -> RendererBinding -> WidgetsBinding眯牧,從而依次完成各個 Binding 的初始化相關工作蹋岩。
RendererBinding
mixin RendererBinding on BindingBase,
{
@override
void initInstance() {
super.initInstance();
_pipelineOwner = PipelineOwner(
……………
);
……………
initRenderView(){
renderView = RenderView(
configuration:createViewConfiguration(),
window:window
);
……………
}
}
}
}
PipelineOwner是渲染管道,它在widget渲染的階段有重要的作用学少,具體的會在后續(xù)的渲染繪制會著重分析.
RenderView 就是我們屏幕真實顯示的那個View剪个,Flutter是單頁面的UI框架,renderView就是這個時間點被初始化出來的版确。它是Render tree 的根節(jié)點扣囊,同時將當前設備的物理屏幕信息配置上。
SemanticsBinding
渲染輔助類綁定绒疗,主要負責關聯語義樹與Flutter Engine侵歇。Flutter維護了一個 semantic tree(語義樹),頁面構建的時候會根據各Widget的語義描述構建一棵 semantic tree吓蘑。如在Image組件中配置 semanticLabel 語義內容惕虑,用戶在IOS/Android手機開啟無障礙功能時,觸摸到該 Image 時通過語義樹查找到對應的語義描述交給Flutter Engine士修,實現讀屏等功能枷遂。對應Semantics widget樱衷,給子Widget定義語義棋嘲,一些安卓自動化無法識別flutter上的widget,通過Semantics 定義語義就可以識別出來了
PaintingBinding
監(jiān)聽系統(tǒng)字體變化事件
ServicesBinding
@override
void initInstances() {
super.initInstances();
_instance = this;
// 構建一個用于platform與flutter層通信的 BinaryMessenger
_defaultBinaryMessenger = createBinaryMessenger();
// 設置window監(jiān)聽回調矩桂,處理platform發(fā)送的消息
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
initLicenses();
// 設置處理platform發(fā)送的系統(tǒng)消息的 Handler
SystemChannels.system.setMessageHandler(handleSystemMessage);
// 設置AppLifecycleState生命周期回調
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
// AppLifecycleState 為 resumed 和 inactive 時才允許響應Vsync信號進行繪制
readInitialLifecycleStateFromNativeWindow();
}
ServicesBinding的初始化的工作主要是兩個:
- platform與flutter層通信相關服務的初始化(比如讀取asset內的資源就是通過defaultBinaryMessenger 也是內部默認的channel使用的消息對象 )
- 注冊監(jiān)聽了flutter app的生命周期變化事件沸移,根據生命周期狀態(tài)決定是否允許發(fā)起繪制任務
SchedulerBinding
繪制調度綁定,繪制渲染流程會詳細分析,也可關注文后的繪制流程時序圖
GestureBinding
手勢事件綁定,主要處理觸屏幕指針事件的分發(fā)以及事件最終回調處理侄榴。
綁定根節(jié)點(scheduleAttachRootWidget)
@protected
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
// 將傳入的Widget綁定RenderView根節(jié)點上
attachRootWidget(rootWidget);
});
}
attachRootWidget源碼:
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement<RenderBox>);
}
先是通過傳入的 rootWidget 及 RenderView 實例化了一個RenderObjectToWidgetAdapter對象雹锣,而RenderObjectToWidgetAdapter是繼承自RenderObjectWidget,即創(chuàng)建了Widget樹的根節(jié)點癞蚕。繼續(xù)調用 attachToRenderTree:
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) {
if (element == null) {
owner.lockState(() {
// 創(chuàng)建了一個RenderObjectToWidgetElement實例作為element tree的根節(jié)點
element = createElement();
assert(element != null);
// 綁定BuildOwner
element.assignOwner(owner);
});
// 標記需要構建的element蕊爵,并rebuild
owner.buildScope(element, () {
element.mount(null, null);
});
SchedulerBinding.instance.ensureVisualUpdate();
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element;
}
@override
void mount(Element parent, dynamic newSlot){
………
_rebuild();
}
void _rebuild(){
………
_child = updateChild(_child, widget.child. _rootChildSlot);
………
}
}
@override
RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
attachToRenderTree 中通過 createElement() 創(chuàng)建了一個RenderObjectToWidgetElement 實例作為 element tree 的根節(jié)點,并綁定BuildOwner桦山,通過 BuildOwner 構建需要構建的 element攒射。
在mount函數這里會觸發(fā)_rebuild();在_rebuild()里面我們看到了updateChild,updateChildl里有調用inflateWidget方法,inflateWidget這個函數恒水,在這個函數里面就會觸發(fā)StatelessWidget和StatefulWidget的 createElement去創(chuàng)建element ,element又會去調用對應類的mount函數会放,經過一系列的流程之后,又會回到inflateWidget這個函數中钉凌,再次觸發(fā)新的mount函數咧最,形成一個層層調用,不斷創(chuàng)建parentElement到childElement的過程,這個過程完成了element tree的構建。
繪制熱身幀(scheduleWarmUpFrame)
void scheduleWarmUpFrame() {
if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)
return;
_warmUpFrame = true;
Timeline.startSync('Warm-up frame');
final bool hadScheduledFrame = _hasScheduledFrame;
Timer.run(() {
assert(_warmUpFrame);
handleBeginFrame(null);
});
Timer.run(() {
assert(_warmUpFrame);
handleDrawFrame();
resetEpoch();
_warmUpFrame = false;
if (hadScheduledFrame)
scheduleFrame();
});
lockEvents(() async {
await endOfFrame;
Timeline.finishSync();
});
}
熱身幀是通過handleBeginFrame矢沿、handleDrawFrame這兩個回調來進行繪制流程滥搭。handleBeginFrame處理動畫相關邏輯,動畫回調后并不立即執(zhí)行動畫捣鲸,而是改變了animation.value论熙,并調用setSate()來發(fā)起繪制請求。動畫的過程就是在 Vsync 信號到來時根據動畫進度計算出對應的 value摄狱,而對應的 Widget 也會隨著 animation.value 的變化而重建脓诡,從而形成動畫,和Android的屬性動畫原理差不多媒役。handleBeginFrame處理完后祝谚,會優(yōu)先處理microTask任務隊列。然后才是event Task酣衷,window.onDrawFrame()交惯,對應SchedulerBinding.handleDrawFrame()。(Timer任務會加入到event queue穿仪,flutter的事件處理機制是優(yōu)先處理 micro queue 中任務)
void handleDrawFrame() {
assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
Timeline.finishSync(); // end the "Animate" phase
try {
// 處理Persistent類型回調,主要包括build\layout\draw流程
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
// 注釋1
_invokeFrameCallback(callback, _currentFrameTimeStamp);
// 處理Post-Frame回調席爽,主要是狀態(tài)清理,準備調度下一幀繪制請求
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp);
} finally {
// 處理完成啊片,設置狀態(tài)為idle
_schedulerPhase = SchedulerPhase.idle;
Timeline.finishSync(); // end the Frame
assert(() {
if (debugPrintEndFrameBanner)
debugPrint('?' * _debugBanner.length);
_debugBanner = null;
return true;
}());
_currentFrameTimeStamp = null;
}
}
// RendererBinding
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
_mouseTracker.schedulePostFrameCheck();
}
void drawFrame() {
assert(renderView != null);
// 布局
pipelineOwner.flushLayout();
// 更新 RenderObject 中需要繪制的內容
pipelineOwner.flushCompositingBits();
// 繪制
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
// 產生這一幀的數據Scene只锻,由window.render交給Engine,最終顯示到屏幕(發(fā)送數據到GPU)紫谷。
renderView.compositeFrame();
// 將語義樹發(fā)送到操作系統(tǒng)
pipelineOwner.flushSemantics();
_firstFrameSent = true;
}
}
// WidgetsBinding
void drawFrame() {
...
try {
if (renderViewElement != null)
//調用BuildOwner.buildScope開始構建
buildOwner.buildScope(renderViewElement);
//調用RendererBinding.drawFrame齐饮,開始布局、繪制階段笤昨。
super.drawFrame();
//從element tree中移除不需要的element祖驱,unmount
buildOwner.finalizeTree();
} finally {
...
}
}
SchedulerBinding.scheduleWarmUpFrame
-> SchedulerBinding.handleBeginFrame 處理動畫
-> SchedulerBinding.handleDrawFrame
-----> WidgetBinding.drawFrame 通過 buildOwner 構建組件
-----> RendererBinding.drawFrame 通過 pipelineOwner 完成組件布局和繪制
-----> renderView.compositeFrame 發(fā)送 Scene 到GPU
歡迎拍磚,交流瞒窒!