Flutter 是重寫了一整套包括底層渲染邏輯和上層開發語言的完整解決方案。架構
Flutter 和其餘跨平臺方案的本質區別:app
React Native 之類的框架,只是經過 JavaScript 虛擬機擴展調用系統組件,由 Android 和 iOS 系統進行組件的渲染;框架
Flutter 則是本身完成了組件渲染的閉環。佈局
在計算機系統中,CPU 負責圖像數據計算,GPU 負責圖像數據渲染,而顯示器則負責最終圖像顯示。 CPU 把計算好的、須要顯示的內容交給 GPU,由 GPU 完成渲染後放入幀緩衝區,隨後視頻控制器根據垂直同步信號(VSync)以每秒 60 次的速度,從幀緩衝區讀取幀數據交由顯示器完成圖像顯示。性能
Skia 是一款用 C++ 開發的、性能彪悍的 2D 圖像繪製引擎,架構於 Skia 之上的 Flutter,也所以擁有了完全的跨平臺渲染能力。優化
頁面中的各界面元素(Widget)以樹的形式組織,即控件樹。Flutter 經過控件樹中的每一個控件建立不一樣類型的渲染對象,組成渲染對象樹。而渲染對象樹在 Flutter 的展現過程分爲四個階段:佈局、繪製、合成和渲染。動畫
Flutter 採用深度優先機制遍歷渲染對象樹,決定渲染對象樹中各渲染對象在屏幕上的位置和尺寸。在佈局過程當中,渲染對象樹中的每一個渲染對象都會接收父對象的佈局約束參數,決定本身的大小,而後父對象按照控件邏輯決定各個子對象的位置,完成佈局過程。操作系統
爲了防止因子節點發生變化而致使整個控件樹從新佈局,Flutter 加入了一個機制——佈局邊界(Relayout Boundary),能夠在某些節點自動或手動地設置佈局邊界,當邊界內的任何對象發生從新佈局時,不會影響邊界外的對象,反之亦然。佈局完成後,渲染對象樹中的每一個節點都有了明確的尺寸和位置。Flutter 會把全部的渲染對象繪製到不一樣的圖層上。與佈局過程同樣,繪製過程也是深度優先遍歷,並且老是先繪製自身,再繪製子節點。插件
如下圖爲例:節點 1 在繪製完自身後,會再繪製節點 2,而後繪製它的子節點 三、4 和 5,最後繪製節點 6。線程
能夠看到,因爲一些其餘緣由(好比,視圖手動合併)致使 2 的子節點 5 與它的兄弟節點 6 處於了同一層,這樣會致使當節點 2 須要重繪的時候,與其無關的節點 6 也會被重繪,帶來性能損耗。爲了解決這一問題,Flutter 提出了與佈局邊界對應的機制——重繪邊界(Repaint Boundary)。在重繪邊界內,Flutter 會強制切換新的圖層,這樣就能夠避免邊界內外的互相影響,避免無關內容置於同一圖層引發沒必要要的重繪。
重繪邊界的一個典型場景是 Scrollview。ScrollView 滾動的時候須要刷新視圖內容,從而觸發內容重繪。而當滾動內容重繪時,通常狀況下其餘內容是不須要重繪的,這時候重繪邊界就派上用場了。終端設備的頁面愈來愈複雜,所以 Flutter 的渲染樹層級一般不少,直接交付給渲染引擎進行多圖層渲染,可能會出現大量渲染內容的重複繪製,因此還須要先進行一次圖層合成,即將全部的圖層根據大小、層級、透明度等規則計算出最終的顯示效果,將相同的圖層歸類合併,簡化渲染樹,提升渲染效率。
合併完成後,Flutter 會將幾何圖層數據交由 Skia 引擎加工成二維圖像數據,最終交由 GPU 進行渲染,完成界面的展現。
首先,咱們打開 Android Studio,建立一個 Flutter 工程應用 flutter_app。Flutter 會根據自帶的應用模板,自動生成一個簡單的計數器示例應用 Demo。
Flutter 會將相關的依賴和構建產物注入這兩個子工程,最終集成到各自的項目中。而咱們開發的 Flutter 代碼,最終則會以原生工程的形式運行。
下面是Demo代碼流程圖
須要注意的是:狀態的更改必定要配合使用 setState。Widget 只是視圖的「配置信息」,是數據的映射,是「只讀」的。對於 StatefulWidget 而言,當數據改變的時候,咱們須要從新建立 Widget 去更新界面,這也就意味着 Widget 的建立銷燬會很是頻繁。
爲此,Flutter 對這個機制作了優化,其框架內部會經過一箇中間層去收斂上層 UI 配置對底層真實渲染的改動,從而最大程度下降對真實渲染視圖的修改,提升渲染效率,而不是上層 UI 配置變了就須要銷燬整個渲染視圖樹重建。