Flutter框架分析(一)-- 總覽和Window

ad6623發表於2019-03-06

Flutter框架分析分析系列文章:

《Flutter框架分析(一)-- 總覽和Window》

《Flutter框架分析(二)-- 初始化》

《Flutter框架分析(三)-- Widget,Element和RenderObject》

《Flutter框架分析(四)-- Flutter框架的執行》

前言

在熟悉了Flutter app開發以後,我們的好奇心會驅使對Flutter框架是如何執行產生諸多疑問,Flutter是如何運轉的?Widget到底是什麼東西?RenderObject又是個什麼鬼?runApp()之後發生了什麼?呼叫sateState()之後頁面又是如何重新整理的?要解答這些問題,就需要學習一下Flutter框架的原始碼。為此我會基於原始碼寫一系列文章來分析一下Flutter框架。本文是第一篇,主要是先介紹一下Flutter框架的總覽和基礎--Window

總覽

Flutter app的頁面是如何顯示到螢幕上的呢?是什麼驅動Flutter app重新整理介面,播放動畫以及響應觸控事件呢?這一過程可以用下圖來描述。

rendering pipline
在Flutter框架中存在著一個渲染流水線(Rendering pipline)。這個渲染流水線是由垂直同步訊號(Vsync)驅動的,而Vsync訊號是由系統提供的,如果你的Flutter app是執行在Android上的話,那Vsync訊號就是我們熟悉的Android的那個Vsync訊號。當Vsync訊號到來以後,Flutter 框架會按照圖裡的順序執行一系列動作: 動畫(Animate)、構建(Build)、佈局(Layout)和繪製(Paint),最終生成一個場景(Scene)之後送往底層,由GPU繪製到螢幕上。

  • 動畫(Animate)階段:因為動畫會隨每個Vsync訊號的到來而改變狀態(State),所以動畫階段是流水線的第一個階段。
  • 構建(Build)在這個階段Flutter,在這個階段那些需要被重新構建的Widget會在此時被重新構建。也就是我們熟悉的StatelessWidget.build()或者State.build()被呼叫的時候。
  • 佈局(Layout)階段,這時會確定各個顯示元素的位置,尺寸。此時是RenderObject.performLayout()被呼叫的時候。
  • 繪製(Paint)階段,此時是RenderObject.paint()被呼叫的時候。

以上是整個渲染流水線的一個大致的工作過程。

Flutter app只有在狀態發生變化的時候需要觸發渲染流水線。當你的app什麼都不做的時候是不需要重新渲染頁面的。所以,Vsync訊號需要Flutter app去排程。比如我們都知道如果你的某個頁面需要發生變化的時候有可能會呼叫State.setState(),這個呼叫Flutter框架最終會發起一個排程Vsync訊號的請求給底層。然後底層會在Vsync訊號到來的時候驅動渲染流水線開始運作,最後把新的頁面顯示到螢幕上。

Flutter整體架構如下圖所示:

Flutter架構
可見整個Flutter架構是分為兩部分的。上層的框架(Framework)部分和底層的引擎(Engine)部分。

  • 框架(Framework)部分是用Dart語言寫的,也是本系列文章主要涉及的部分。
  • 引擎(Engine)部分是用C++實現的。引擎為框架提供支撐,也是連線框架和系統(Android/iOS)的橋樑。

觸發渲染流水線的Vsync訊號是來自引擎,渲染完成以後的場景也是要送入引擎來顯示,並且Vsync訊號的排程也是框架通過引擎來通知系統的。渲染流程從框架和引擎互動的角度用一個示意圖來表示就是下面這個樣子:

渲染排程示意圖

  • 框架通知引擎(scheduleFrame)需要排程一幀。
  • 在系統的Vsync訊號到來以後,引擎會首先會回撥框架的_beginFrame函式。此時框架的渲染流水線進入動畫(Animate)階段,
  • 在動畫(Animate)階段階段完成以後。引擎會處理完微任務佇列,接著再回撥框架的_drawFrame函式。渲染流水線繼續按序執行構建、佈局和繪製。
  • 繪製結束以後,框架呼叫render將繪製完成的場景送入引擎以顯示到螢幕上。

在前端開發中我們都會對於使用者介面有一個視窗(Window)的概念,我們寫的程式的UI都是容納在視窗中的,視窗是框架的根基。介面的繪製,使用者輸入的事件的處理等等都是要通過視窗來管理。Flutter也不例外。上述框架和引擎渲染互動流程也是統一納入視窗管理的。所以要了解Flutter框架,首先得從Flutter的視窗開始。

Window

Flutter中的Window來自庫dart:ui。相關原始碼在window.dart中。

首先,在Flutter中,Window是個單例:

/// The [Window] singleton. This object exposes the size of the display, the
/// core scheduler API, the input event callback, the graphics drawing API, and
/// other such core services.
final Window window = new Window._();
複製程式碼

Window單例對上層提供螢幕尺寸,排程介面,輸入事件回撥,圖形繪製介面以及其他一些核心服務。總體來說,window集中提供了Flutter引擎中和圖形介面相關的介面。

Window中和渲染流水線相關的api如下:

// vcync訊號到來以後的回撥
FrameCallback _onBeginFrame;
VoidCallback _onDrawFrame;
// 請求engine排程一幀
void scheduleFrame() native 'Window_scheduleFrame';
// 繪製完成後將場景送入engine顯示
void render(Scene scene) native 'Window_render';
複製程式碼

大家注意一下函式名稱後面的native關鍵字,表明這個函式是呼叫到engine層的。和Android中的jni呼叫類似。

除渲染相關的API,window中還有一些其他重要的API也列一下:

//觸控事件的回撥
PointerDataPacketCallback _onPointerDataPacket;
// 獲取啟動時初始頁面的路由
String _defaultRouteName() native 'Window_defaultRouteName';
// 傳送PlatfromMessage。這個是Platform channels機制的一部分
String _sendPlatformMessage(String name,
                              PlatformMessageResponseCallback callback,
                              ByteData data) native 'Window_sendPlatformMessage';
//收到platform message後的回撥
PlatformMessageCallback _onPlatformMessage;
複製程式碼

還有一些和locale,accessbility的相關的API就不列出來了。

總結

至此,Flutter的Window就大概給大家介紹完了。可見Window其實並不複雜,基本上只是對engine層對上提供的和使用者介面相關的介面的封裝。Flutter框架是基於Window建立起來的。如果你願意的話,完全可以基於Window搭建起自己的一套框架來取代Flutter :)。在瞭解了Flutter的渲染流水線和視窗這個基礎設施之後。接下來我們會以此為基礎,開始奇妙的Flutter框架之旅,敬請期待。

相關文章