1. 10分鐘了解Flutter跨平臺運行原理!

        共 3969字,需瀏覽 8分鐘

         ·

        2021-10-01 09:32


        導(dǎo)語 | 本文將從選型、簡介和運行原理三大部分為你介紹Flutter的相關(guān)概念,希望能站在框架設(shè)計和實現(xiàn)原理的高度,帶領(lǐng)大家去理解Flutter區(qū)別其他跨平臺解決方案的關(guān)鍵所在。


        一、為什么選擇Flutter


        隨著無線時代的來臨,怎么樣用最標準化的手段能夠讓更多的人開發(fā)這個頁面、怎么樣能夠提供像H5一樣標準的頁面,成為大前端時代開發(fā)者們最關(guān)心的事情。



        我們把時間線拉長,來看看移動端跨平臺技術(shù)經(jīng)過了一個怎樣的發(fā)展史:下面主要介紹在這個發(fā)展過程中跨平臺技術(shù)有了哪些進步或者做了哪些優(yōu)化。




        Ionic/Cordova(Hybrid): 在技術(shù)原理上的核心是,將原生的一些能力通過JSBridge封裝給Web來調(diào)用,擴充了Web應(yīng)用能力。但是這種方法有兩個不足,一是依賴客戶端,二是在性能和體驗上都非常依賴于Web端。因此,整體上的體驗不可預(yù)知。目前這個技術(shù)還經(jīng)常被應(yīng)用到,例如,當前App內(nèi)會提供白名單域名和可調(diào)用的JSBridge方法,由此來增強H5與客戶端交互能力,從而提升App內(nèi)H5的靈活性。


        React Native/Weex: 在原來的Hybrid的JSBridge基礎(chǔ)上進行改進,將JavaScript的界面以及交互轉(zhuǎn)化為Native的控件,從而在體驗上和原生界面基本一致。但因為是JIT模式,因此需要頻繁地在JavaScript與Native之間進行通信,從而會有一定的性能損耗影響,導(dǎo)致體驗上與原生會有一些差異。


        Flutter: 取長補短,結(jié)合了之前的一些優(yōu)點,解決了與Native之間通信的問題,同時也有了自渲染模式(框架自身實現(xiàn)了一套UI基礎(chǔ)框架,與原來的渲染模式基本一致)。從而在體驗和性能上相對之前的兩種框架表現(xiàn)都較好。


        選擇Flutter并不是為了代替iOS或者Android,而是做一個技術(shù)互補,比如,F(xiàn)lutter負責(zé)業(yè)務(wù)功能,而iOS和Android則負責(zé)部分的底層交互提供服務(wù)給到Flutter應(yīng)用,這里大膽預(yù)測一下未來跨端技術(shù)團隊的組成: 




        二、Flutter簡介


        Flutter是一款移動應(yīng)用程序跨平臺框架,使用一種語言(Dart)編寫的同一份代碼可以生成iOS和Android兩個高性能、高保真的應(yīng)用程序。



        Flutter目標是使開發(fā)人員能夠交付在不同平臺上都感覺自然流暢的高性能應(yīng)用程序。兼容滾動行為、排版、圖標等方面的差異。那么Flutter是如何編譯成原生app的呢?


        Flutter不借助原生的渲染能力,而是自己實現(xiàn)了一套與Android和iOS一樣的渲染原理,從而在性能上與原生平臺保持基本一致。不過這里由于目前 Flutter只是一個UI框架,因此在原生功能方面還是需要依賴原生平臺,這也是它存在的一些問題。




        三、Flutter運行原理


        如前面已提到的那樣,F(xiàn)lutter是重寫了一整套包括底層渲染邏輯和上層開發(fā)語言的完整解決方案。這樣不僅可以保證視圖渲染在Android和iOS上的高度一致性(即高保真),在代碼執(zhí)行效率和渲染性能上也可以媲美原生App的體驗(即高性能)。那Flutter是怎么運行的呢?


        我們從圖像顯示的基本原理說起。


        在計算機系統(tǒng)中,圖像的顯示需要CPU、GPU和顯示器一起配合完成:CPU負責(zé)圖像數(shù)據(jù)計算,GPU負責(zé)圖像數(shù)據(jù)渲染,而顯示器則負責(zé)最終圖像顯示。


        CPU把計算好的、需要顯示的內(nèi)容交給GPU,由GPU完成渲染后放入幀緩沖區(qū),隨后視頻控制器根據(jù)垂直同步信號(VSync)以每秒60次的速度,從幀緩沖區(qū)讀取幀數(shù)據(jù)交由顯示器完成圖像顯示。


        操作系統(tǒng)在呈現(xiàn)圖像時遵循了這種機制,而Flutter作為跨平臺開發(fā)框架也采用了這種底層方案。下面有一張更為詳盡的示意圖來解釋Flutter的繪制原理。



        可以看到,F(xiàn)lutter關(guān)注如何盡可能快地在兩個硬件時鐘的VSync信號之間計算并合成視圖數(shù)據(jù),然后通過Skia交給GPU渲染:UI線程使用Dart來構(gòu)建視圖結(jié)構(gòu)數(shù)據(jù),這些數(shù)據(jù)會在GPU線程進行圖層合成,隨后交給Skia引擎加工成GPU數(shù)據(jù),而這些數(shù)據(jù)會通過OpenGL最終提供給GPU渲染。


        在進一步學(xué)習(xí)Flutter之前,我們有必要了解下構(gòu)建Flutter的關(guān)鍵技術(shù),即Skia和Dart。


        備注


        1. Skia是一款用C++開發(fā)的、性能彪悍的2D圖像繪制引擎,Skia保證了同一套代碼調(diào)用在Android和iOS平臺上的渲染效果是完全一致的。


        2. Dart是一個專注于前端(mobile/web)UI(用戶交互)開發(fā)的強類型語言。


        在了解了Flutter的基本運作機制后,我們再來深入了解一下Flutter的實現(xiàn)原理。


        首先,我們來看一下Flutter的架構(gòu)圖。我希望通過這張圖以及對應(yīng)的解讀,你能在開始學(xué)習(xí)的時候就建立起對Flutter的整體印象。


        注:此圖引自Flutter System Overview


        Flutter架構(gòu)采用分層設(shè)計,從下到上分為三層,依次為Embedder、Engine和Framework。

        Embedder是操作系統(tǒng)適配層,實現(xiàn)了渲染Surface設(shè)置、線程設(shè)置以及平臺插件等平臺相關(guān)特性的適配。從這里我們可以看到,F(xiàn)lutter平臺相關(guān)特性并不多,這就使得從框架層面保持跨端一致性的成本相對較低。


        Engine層主要包含Skia、Dart和Text,實現(xiàn)了Flutter的渲染引擎、文字排版、事件處理和Dart運行時等功能。Skia和Text為上層接口提供了調(diào)用底層渲染和排版的能力,Dart則為Flutter提供了運行時調(diào)用Dart和渲染引擎的能力。而Engine層的作用,則是將它們組合起來,從它們生成的數(shù)據(jù)中實現(xiàn)視圖渲染。


        Framework層則是一個用Dart實現(xiàn)的UI SDK,包含了動畫、圖形繪制和手勢識別等功能。為了在繪制控件等固定樣式的圖形時提供更直觀、更方便的接口,F(xiàn)lutter還基于這些基礎(chǔ)能力,根據(jù)Material和Cupertino兩種視覺設(shè)計風(fēng)格封裝了一套UI組件庫。我們在開發(fā)Flutter的時候,可以直接使用這些組件庫。


        接下來,以界面渲染過程為例,介紹Flutter是如何工作的。


        頁面中的各界面元素(Widget)以樹的形式組織,即控件樹。Flutter通過控件樹中的每個控件創(chuàng)建不同類型的渲染對象,組成渲染對象樹。而渲染對象樹在Flutter的展示過程分為三個階段:布局、繪制、合成和渲染。


        (一)布局


        Flutter采用深度優(yōu)先機制遍歷渲染對象樹,決定渲染對象樹中各渲染對象在屏幕上的位置和尺寸。在布局過程中,渲染對象樹中的每個渲染對象都會接收父對象的布局約束參數(shù),決定自己的大小,然后父對象按照控件邏輯決定各個子對象的位置,完成布局過程。



        為了防止因子節(jié)點發(fā)生變化而導(dǎo)致整個控件樹重新布局,F(xiàn)lutter加入了一個機制——布局邊界(Relayout Boundary),可以在某些節(jié)點自動或手動地設(shè)置布局邊界,當邊界內(nèi)的任何對象發(fā)生重新布局時,不會影響邊界外的對象,反之亦然。




        (二)繪制


        布局完成后,渲染對象樹中的每個節(jié)點都有了明確的尺寸和位置。Flutter會把所有的渲染對象繪制到不同的圖層上。與布局過程一樣,繪制過程也是深度優(yōu)先遍歷,而且總是先繪制自身,再繪制子節(jié)點。


        以下圖為例:節(jié)點1在繪制完自身后,會再繪制節(jié)點2,然后繪制它的子節(jié)點3、4和5,最后繪制節(jié)點6。



        可以看到,由于一些其他原因(比如,視圖手動合并)導(dǎo)致2的子節(jié)點5與它的兄弟節(jié)點6處于了同一層,這樣會導(dǎo)致當節(jié)點2需要重繪的時候,與其無關(guān)的節(jié)點6也會被重繪,帶來性能損耗。


        為了解決這一問題,F(xiàn)lutter提出了與布局邊界對應(yīng)的機制——重繪邊界(Repaint Boundary)。在重繪邊界內(nèi),F(xiàn)lutter會強制切換新的圖層,這樣就可以避免邊界內(nèi)外的互相影響,避免無關(guān)內(nèi)容置于同一圖層引起不必要的重繪。



        重繪邊界的一個典型場景是Scrollview。ScrollView滾動的時候需要刷新視圖內(nèi)容,從而觸發(fā)內(nèi)容重繪。而當滾動內(nèi)容重繪時,一般情況下其他內(nèi)容是不需要重繪的,這時候重繪邊界就派上用場了。



        (三)合成和渲染


        終端設(shè)備的頁面越來越復(fù)雜,因此Flutter的渲染樹層級通常很多,直接交付給渲染引擎進行多圖層渲染,可能會出現(xiàn)大量渲染內(nèi)容的重復(fù)繪制,所以還需要先進行一次圖層合成,即將所有的圖層根據(jù)大小、層級、透明度等規(guī)則計算出最終的顯示效果,將相同的圖層歸類合并,簡化渲染樹,提高渲染效率。


        合并完成后,F(xiàn)lutter會將幾何圖層數(shù)據(jù)交由Skia引擎加工成二維圖像數(shù)據(jù),最終交由GPU進行渲染,完成界面的展示。



        四、總結(jié)


        咱們從各種業(yè)界主流跨端方案與Flutter的對比開始,到Flutter的簡要介紹以及Flutter的運行機制,并以界面渲染過程為例,從布局、繪制、合成和渲染三個階段講述了Flutter的實現(xiàn)原理。相信大家對Flutter已經(jīng)有一個整體認知,趕快一起上手操作起來吧!



         作者簡介


        賓俊文

        騰訊IEG直播業(yè)務(wù)部 前端工程師

        騰訊IEG直播業(yè)務(wù)部前端工程師。正在為成為極具影響力的工程師而努力!



         推薦閱讀


        如何在C++20中實現(xiàn)Coroutine及相關(guān)任務(wù)調(diào)度器?(實例教學(xué))

        拒絕千篇一律,這套Go錯誤處理的完整解決方案值得一看!

        10個技巧!實現(xiàn)Vue.js極致性能優(yōu)化(建議收藏)

        為什么WebAssembly不是JavaScript的終結(jié)者,而是它的“助推器”?






        瀏覽 93
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 超薄肉色丝袜足j调教99 | 免费在线成人网站 | 久久成人AV电影 | 男生操女生免费视频 | 国产最新美女精品视频网站免费观看网址大全 |