<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          10分鐘了解Flutter跨平臺(tái)運(yùn)行原理!

          共 3969字,需瀏覽 8分鐘

           ·

          2021-10-01 09:32


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


          一、為什么選擇Flutter


          隨著無(wú)線(xiàn)時(shí)代的來(lái)臨,怎么樣用最標(biāo)準(zhǔn)化的手段能夠讓更多的人開(kāi)發(fā)這個(gè)頁(yè)面、怎么樣能夠提供像H5一樣標(biāo)準(zhǔn)的頁(yè)面,成為大前端時(shí)代開(kāi)發(fā)者們最關(guān)心的事情。



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




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


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


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


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




          二、Flutter簡(jiǎn)介


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



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


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




          三、Flutter運(yùn)行原理


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


          我們從圖像顯示的基本原理說(shuō)起。


          在計(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ù)垂直同步信號(hào)(VSync)以每秒60次的速度,從幀緩沖區(qū)讀取幀數(shù)據(jù)交由顯示器完成圖像顯示。


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



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


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


          備注


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


          2. Dart是一個(gè)專(zhuān)注于前端(mobile/web)UI(用戶(hù)交互)開(kāi)發(fā)的強(qiáng)類(lèi)型語(yǔ)言。


          在了解了Flutter的基本運(yùn)作機(jī)制后,我們?cè)賮?lái)深入了解一下Flutter的實(shí)現(xiàn)原理。


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


          注:此圖引自Flutter System Overview


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

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


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


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


          接下來(lái),以界面渲染過(guò)程為例,介紹Flutter是如何工作的


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


          (一)布局


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



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




          (二)繪制


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


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



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


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



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



          (三)合成和渲染


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


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



          四、總結(jié)


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



           作者簡(jiǎn)介


          賓俊文

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

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



           推薦閱讀


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

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

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

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






          瀏覽 93
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩AV毛片 | 99伊人网 | 精品人妻无码一区二区三区91 | 西西444| 色撸撸在线视频 |