Flutter 出現(xiàn)的歷史背景
- 為不同的操作系統(tǒng)開發(fā)擁有相同功能的應(yīng)用程序,開發(fā)人員只有兩個選擇:
①使用原生開發(fā)語言(即 Java 和 Objective-C),針對不同平臺分別進(jìn)行開發(fā)。
②使用跨平臺解決方案,對不同平臺進(jìn)行統(tǒng)一開發(fā)。 - 最成功的跨平臺開發(fā)方案其實(shí)是依托于瀏覽器控件的 Web。瀏覽器保證了 99% 的概率下 Web 的需求都是可以實(shí)現(xiàn)的,不需要業(yè)務(wù)將就“技術(shù)”。不過,Web 最大的問題在于它的性能和體驗(yàn)與原生開發(fā)存在肉眼可感知的差異,因此并不適用于對體驗(yàn)要求較高的場景。對于用戶體驗(yàn)更接近于原生的 React Native,對業(yè)務(wù)的支持能力卻還不到瀏覽器的 5%,僅適用于中低復(fù)雜度的低交互類頁面。
- Flutter 是構(gòu)建 Google 物聯(lián)網(wǎng)操作系統(tǒng) Fuchsia 的 SDK,主打跨平臺、高保真、高性能。一套代碼可以同時運(yùn)行在 iOS 和 Android 平臺。 Flutter 使用 Native 引擎渲染視圖,并提供了豐富的組件和接口。
Flutter 是怎么運(yùn)轉(zhuǎn)的?
- Flutter 是重寫了一整套包括底層渲染邏輯和上層開發(fā)語言的完整解決方案。這樣不僅可以保證視圖渲染在 Android 和 iOS 上的高度一致性(即高保真),在代碼執(zhí)行效率和渲染性能上也可以媲美原生 App 的體驗(yàn)(即高性能)。
- React Native 之類的框架,只是通過 JavaScript 虛擬機(jī)擴(kuò)展調(diào)用系統(tǒng)組件,由 Android 和 iOS 系統(tǒng)進(jìn)行組件的渲染;
-
Flutter 則是自己完成了組件渲染的閉環(huán):
①在計(jì)算機(jī)系統(tǒng)中,圖像的顯示需要 CPU、GPU 和顯示器一起配合完成:CPU 負(fù)責(zé)圖像數(shù)據(jù)計(jì)算,GPU 負(fù)責(zé)圖像數(shù)據(jù)渲染,而顯示器則負(fù)責(zé)最終圖像顯示。
②CPU 把計(jì)算好的、需要顯示的內(nèi)容交給 GPU,由 GPU 完成渲染后放入幀緩沖區(qū),隨后視頻控制器根據(jù)垂直同步信號(VSync)以每秒 60 次的速度,從幀緩沖區(qū)讀取幀數(shù)據(jù)交由顯示器完成圖像顯示。
③操作系統(tǒng)在呈現(xiàn)圖像時遵循了這種機(jī)制,而 Flutter 作為跨平臺開發(fā)框架也采用了這種底層方案。下面有一張更為詳盡的示意圖來解釋 Flutter 的繪制原理。
image.png
Skia 是什么?
- Flutter 只關(guān)心如何向 GPU 提供視圖數(shù)據(jù),而 Skia 就是它向 GPU 提供視圖數(shù)據(jù)的好幫手。
- Skia 是一款用 C++ 開發(fā)的、性能彪悍的 2D 圖像繪制引擎,其前身是一個向量繪圖軟件。2005 年被 Google 公司收購后,因?yàn)槠涑錾睦L制表現(xiàn)被廣泛應(yīng)用在 Chrome 和 Android 等核心產(chǎn)品上。Skia 在圖形轉(zhuǎn)換、文字渲染、位圖渲染方面都表現(xiàn)卓越,并提供了開發(fā)者友好的 API。
- 因此,架構(gòu)于 Skia 之上的 Flutter,也因此擁有了徹底的跨平臺渲染能力。通過與 Skia 的深度定制及優(yōu)化,F(xiàn)lutter 可以最大限度地抹平平臺差異,提高渲染效率與性能。
- 底層渲染能力統(tǒng)一了,上層開發(fā)接口和功能體驗(yàn)也就隨即統(tǒng)一了,開發(fā)者再也不用操心平臺相關(guān)的渲染特性了。也就是說,Skia 保證了同一套代碼調(diào)用在 Android 和 iOS 平臺上的渲染效果是完全一致的。
為什么是 Dart?而不是更為流行的JavaScript
- Dart 語言開發(fā)組就在隔壁,對于 Flutter 需要的一些語言新特性,能夠快速在語法層面落地實(shí)現(xiàn)。如果選擇了 JavaScript,就必須經(jīng)過各種委員會和瀏覽器提供商漫長的決議。
- Dart 同時支持即時編譯 JIT 和事前編譯 AOT。在開發(fā)期使用 JIT,開發(fā)周期異常短,調(diào)試方式顛覆常規(guī)(支持有狀態(tài)的熱重載);而發(fā)布期使用 AOT,本地代碼的執(zhí)行更高效,代碼性能和用戶體驗(yàn)也更卓越
- Dart 作為一門現(xiàn)代化語言,集百家之長,擁有其他優(yōu)秀編程語言的諸多特性(比如,完善的包管理機(jī)制)。也正是這個原因,Dart 的學(xué)習(xí)成本并不高,很容易上手。
- Dart 避免了搶占式調(diào)度和共享內(nèi)存,可以在沒有鎖的情況下進(jìn)行對象分配和垃圾回收,在性能方面表現(xiàn)相當(dāng)不錯。
Flutter 的原理


以界面渲染過程為例,和你介紹 Flutter 是如何工作的。
頁面中的各界面元素(Widget)以樹的形式組織,即控件樹。Flutter 通過控件樹中的每個控件創(chuàng)建不同類型的渲染對象,組成渲染對象樹。而渲染對象樹在 Flutter 的展示過程分為四個階段:布局、繪制、合成和渲染:
-
布局
①Flutter 采用深度優(yōu)先機(jī)制遍歷渲染對象樹,決定渲染對象樹中各渲染對象在屏幕上的位置和尺寸。Flutter 采用深度優(yōu)先機(jī)制遍歷渲染對象樹,決定渲染對象樹中各渲染對象在屏幕上的位置和尺寸。
image.png
②為了防止因子節(jié)點(diǎn)發(fā)生變化而導(dǎo)致整個控件樹重新布局,F(xiàn)lutter 加入了一個機(jī)制——布局邊界(Relayout Boundary),可以在某些節(jié)點(diǎn)自動或手動地設(shè)置布局邊界,當(dāng)邊界內(nèi)的任何對象發(fā)生重新布局時,不會影響邊界外的對象,反之亦然。
image.png -
繪制
①布局完成后,渲染對象樹中的每個節(jié)點(diǎn)都有了明確的尺寸和位置。Flutter 會把所有的渲染對象繪制到不同的圖層上。與布局過程一樣,繪制過程也是深度優(yōu)先遍歷,而且總是先繪制自身,再繪制子節(jié)點(diǎn)。
②以下圖為例:節(jié)點(diǎn) 1 在繪制完自身后,會再繪制節(jié)點(diǎn) 2,然后繪制它的子節(jié)點(diǎn) 3、4 和 5,最后繪制節(jié)點(diǎn) 6。
image.png
可以看到,由于一些其他原因(比如,視圖手動合并)導(dǎo)致 2 的子節(jié)點(diǎn) 5 與它的兄弟節(jié)點(diǎn) 6 處于了同一層,這樣會導(dǎo)致當(dāng)節(jié)點(diǎn) 2 需要重繪的時候,與其無關(guān)的節(jié)點(diǎn) 6 也會被重繪,帶來性能損耗。
為了解決這一問題,F(xiàn)lutter 提出了與布局邊界對應(yīng)的機(jī)制——重繪邊界(Repaint Boundary)。在重繪邊界內(nèi),F(xiàn)lutter 會強(qiáng)制切換新的圖層,這樣就可以避免邊界內(nèi)外的互相影響,避免無關(guān)內(nèi)容置于同一圖層引起不必要的重繪。
image.png
重繪邊界的一個典型場景是 Scrollview。ScrollView 滾動的時候需要刷新視圖內(nèi)容,從而觸發(fā)內(nèi)容重繪。而當(dāng)滾動內(nèi)容重繪時,一般情況下其他內(nèi)容是不需要重繪的,這時候重繪邊界就派上用場了。 - 合成和渲染
①終端設(shè)備的頁面越來越復(fù)雜,因此 Flutter 的渲染樹層級通常很多,直接交付給渲染引擎進(jìn)行多圖層渲染,可能會出現(xiàn)大量渲染內(nèi)容的重復(fù)繪制,所以還需要先進(jìn)行一次圖層合成,即將所有的圖層根據(jù)大小、層級、透明度等規(guī)則計(jì)算出最終的顯示效果,將相同的圖層歸類合并,簡化渲染樹,提高渲染效率。
②合并完成后,F(xiàn)lutter 會將幾何圖層數(shù)據(jù)交由 Skia 引擎加工成二維圖像數(shù)據(jù),最終交由 GPU 進(jìn)行渲染,完成界面的展示。
學(xué)習(xí) Flutter 需要掌握哪些知識?





