布局ViewGroup原理解析(一):ConstraintLayout

原文:https://mp.weixin.qq.com/s/gGR2itbY7hh9fo61SxaMQQ

文 / Google 開發(fā)者計劃工程師 Takeshi Hagikura

自從在去年的 Google I/O 大會上發(fā)布 ConstraintLayout 以來单绑,我們一直不斷改進該布局的穩(wěn)定性劲妙,完善對布局編輯器的支持获茬。我們還針對 ConstraintLayout 增加了一些新功能,幫助您構(gòu)建不同類型的布局窗轩,例如引入鏈和按比例設(shè)置大小嗅回。

除了這些功能之外汞贸,使用 ConstraintLayout 還可以獲得一項顯著的性能優(yōu)勢。在本文中五督,我們將向您介紹如何從這些性能改進中獲益。

Android 如何繪制視圖瓶殃?

為了更好地理解 ConstraintLayout 的性能充包,我們先回過頭來看看 Android 如何繪制視圖。

當(dāng)用戶將某個 Android 視圖作為焦點時遥椿,Android 框架會指示該視圖進行自我繪制基矮。這個繪制過程包括 3 個階段:

1. 測量

系統(tǒng)自頂向下遍歷視圖樹,以確定每個 ViewGroup 和 View 元素應(yīng)當(dāng)有多大冠场。在測量 ViewGroup 的同時也會測量其子對象家浇。

2. 布局

系統(tǒng)執(zhí)行另一個自頂向下的遍歷操作,每個 ViewGroup 都根據(jù)測量階段中所確定的大小來確定其子對象的位置碴裙。

3. 繪制

系統(tǒng)再次執(zhí)行一個自頂向下的遍歷操作钢悲。對于視圖樹中的每個對象,系統(tǒng)會為其創(chuàng)建一個 Canvas 對象舔株,以便向 GPU 發(fā)送一個繪制命令列表莺琳。這些命令包含系統(tǒng)在前面 2 個階段中確定的 ViewGroup 和 View 對象的大小和位置。

image

測量階段如何遍歷視圖樹的示例

繪制過程中的每個階段都需要對視圖樹執(zhí)行一次自頂向下的遍歷操作督笆。因此芦昔,視圖層次結(jié)構(gòu)中嵌入(或嵌套)的視圖越多,設(shè)備繪制視圖所需的時間和計算功耗也就越多娃肿。通過在 Android 應(yīng)用布局中保持扁平的層次結(jié)構(gòu)咕缎,您可以為應(yīng)用創(chuàng)建響應(yīng)快速而靈敏的界面。

傳統(tǒng)布局層次結(jié)構(gòu)的開銷

請牢記上述解釋料扰,下面我們來創(chuàng)建一個使用 LinearLayout 和 RelativeLayout 對象的傳統(tǒng)布局層次結(jié)構(gòu)凭豪。

image

布局示例

假設(shè)我們想構(gòu)建一個像上圖那樣的布局。如果您使用傳統(tǒng)布局來構(gòu)建晒杈,XML 文件會包含類似于下面這樣的元素層次結(jié)構(gòu)(在本例中嫂伞,我們忽略屬性):

盡管一般來說,這種類型的視圖層次結(jié)構(gòu)都有改進的空間,但您幾乎必定還需要創(chuàng)建一個包含一些嵌套視圖的層次結(jié)構(gòu)帖努。

如前所述撰豺,嵌套的層次結(jié)構(gòu)會給性能造成負面影響。我們使用 Android Studio 的 Systrace 工具來看看嵌套視圖對界面性能到底有何實際影響拼余。我們通過編程方式針對每個 ViewGroup(ConstraintLayout 和 RelativeLayout)調(diào)用了測量和布局階段并在執(zhí)行測量和布局調(diào)用期間觸發(fā)了 Systrace污桦。以下命令可生成一個包含 20 秒間隔周期內(nèi)發(fā)生的關(guān)鍵 Event 的概覽文件,例如開銷巨大的測量/布局階段:

python $ANDROID_HOME/platform-tools/systrace/systrace.py --time=20 -o ~/trace.html gfx view res

有關(guān)如何使用 Systrace 的詳細信息匙监,請參閱使用 Systrace 分析界面性能指南:

https://developer.android.google.cn/studio/profile/systrace.html

Systrace 會自動突出顯示此布局中的(大量)性能問題凡橱,并給出修復(fù)這些問題的建議。通過點擊“Alerts”標簽亭姥,您會發(fā)現(xiàn)稼钩,繪制此視圖層次結(jié)構(gòu)需要反復(fù)執(zhí)行 80 次的測量和布局階段,開銷極為龐大达罗!

觸發(fā)開銷如此龐大的測量和布局階段當(dāng)然很不理想坝撑,如此龐大的繪制 Activity 會導(dǎo)致用戶能夠覺察到丟幀的現(xiàn)象。我們可以得出這樣的結(jié)論:這種嵌套式層次結(jié)構(gòu)和 RelativeLayout(會對其每個子對象重復(fù)測量兩次)的特性導(dǎo)致性能低下氮块。

image

觀察 Systrace 針對使用 RelativeLayout 的布局版本發(fā)出的提醒

您可以在我們的 GitHub 代碼庫中查看我們用來執(zhí)行這些測量的完整代碼:

https://github.com/googlesamples/android-constraint-layout-performance

ConstraintLayout 對象的優(yōu)勢

如果您使用 ConstraintLayout 來構(gòu)建相同的布局绍载,XML 文件會包含類似于下面這樣的元素層次結(jié)構(gòu)(再次忽略屬性):

如本例所示,現(xiàn)在滔蝉,該布局擁有一個完全扁平的層次結(jié)構(gòu)击儡。這是因為 ConstraintLayout 允許您構(gòu)建復(fù)雜的布局,而不必嵌套 View 和 ViewGroup 元素蝠引。

舉個例子阳谍,我們來看一下布局中間的 TextView 和 EditText:

image

使用 RelativeLayout 時,您需要創(chuàng)建一個新的 ViewGroup 來垂直對齊 EditText 和 TextView:

android:layout_marginEnd="8dp" />

通過改用 ConstraintLayout螃概,您只需添加一個從 TextView 基線到 EditText 基線之間的約束矫夯,即可實現(xiàn)同樣的效果,而不必創(chuàng)建另一個 ViewGroup:

image

EditText 和 TextView 之間的約束

在針對我們使用 ConstraintLayout 的布局版本運行 Systrace 工具時吊洼,您會發(fā)現(xiàn)训貌,同樣 20 秒間隔周期內(nèi)執(zhí)行的測量/布局次數(shù)大大減少,開銷也隨之大大減少冒窍。這種性能的改進很有意義递沪,現(xiàn)在,我們保持了扁平的視圖層次結(jié)構(gòu)综液!

image

觀察 Systrace 針對使用 ConstraintLayout 的布局版本發(fā)出的提醒

同樣值得一提的是款慨,我們構(gòu)建 ConstraintLayout 版本的布局時僅僅使用了布局編輯器,而不是手工編輯 XML谬莹。而要使用 RelativeLayout 來實現(xiàn)同樣的視覺效果檩奠,我們很可能必須手工編輯 XML桩了。

測量性能差異

我們使用 Android 7.0(API 級別 24)中引入的 OnFrameMetricsAvailableListener 分析了 ConstraintLayout 和 RelativeLayout 這兩種類型的布局所執(zhí)行的每次測量和布局操作所花費的時間。通過該類埠戳,您可以收集有關(guān)應(yīng)用界面渲染的逐幀時間信息井誉。

通過調(diào)用以下代碼,您可以開始記錄每個幀的界面操作:

window.addOnFrameMetricsAvailableListener(

frameMetricsAvailableListener, frameMetricsHandler);

在能夠獲取時間信息之后乞而,該應(yīng)用觸發(fā) frameMetricsAvailableListener() 回調(diào)送悔。我們對測量/布局的性能感興趣慢显,因此爪模,我們在檢索實際幀的持續(xù)時間時調(diào)用了 FrameMetrics.LAYOUT_MEASURE_DURATION。

Window.OnFrameMetricsAvailableListener {

_, frameMetrics, _ ->

val frameMetricsCopy = FrameMetrics(frameMetrics);

// Layout measure duration in nanoseconds

val layoutMeasureDurationNs =

frameMetricsCopy.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION);

如需詳細了解 FrameMetrics 可以檢索的其他類型的持續(xù)時間信息荚藻,請參閱 FrameMetricsAPI 參考:

https://developer.android.google.cn/reference/android/view/FrameMetrics.html

測量結(jié)果:ConstraintLayout 速度更快

我們的性能比較結(jié)果表明:ConstraintLayout 在測量/布局階段的性能比 RelativeLayout大約高 40%:

image

測量/布局(單位:毫秒屋灌,100 幀的平均值)

這些結(jié)果表明:ConstraintLayout 很可能比傳統(tǒng)布局的性能更出色。不僅如此应狱,ConstraintLayout 還具備其他一些功能共郭,能夠幫助您構(gòu)建復(fù)雜的高性能布局。

有關(guān)詳情疾呻,請參閱使用 ConstraintLayout 構(gòu)建快速響應(yīng)的界面指南:

https://medium.com/google-developers/building-interfaces-with-constraintlayout-3958fa38a9f7

我們建議您在設(shè)計應(yīng)用布局時使用 ConstraintLayout除嘹。在過去,幾乎所有情形下岸蜗,您都需要一個深度嵌套的布局尉咕,因此,ConstraintLayout 應(yīng)當(dāng)成為您優(yōu)化性能和易用性的不二之選璃岳。

附錄:測量環(huán)境 &后續(xù)計劃

上述所有測量均在以下環(huán)境中執(zhí)行:

設(shè)備- Nexus 5X

Android 版本- 8.0

ConstraintLayout 版本- 1.0.2

查看開發(fā)者指南:

https://developer.android.google.cn/training/constraint-layout/index.html

API 參考文檔:

https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout.html

媒體文章:

https://medium.com/google-developers/building-interfaces-with-constraintlayout-3958fa38a9f7

以完全理解 ConstraintLayout 能夠給您帶來什么年缎。再次感謝您,感謝自從我們的

Alpha

版 ConstraintLayout 發(fā)布以來的幾個月里提交反饋和問題的所有同仁铃慷。我們得以在今年早些時候發(fā)布 ConstraintLayout 的 1.0

正式版单芜,離不開您的支持,我們在此謹致以誠摯的謝意犁柜!我們將繼續(xù)改進 ConstraintLayout洲鸠,請您繼續(xù)使用 Android Issue

Tracker 向我們發(fā)送反饋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馋缅,一起剝皮案震驚了整個濱河市扒腕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌股囊,老刑警劉巖袜匿,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稚疹,居然都是意外死亡居灯,警方通過查閱死者的電腦和手機祭务,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怪嫌,“玉大人义锥,你說我怎么就攤上這事⊙颐穑” “怎么了拌倍?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長噪径。 經(jīng)常有香客問我柱恤,道長,這世上最難降的妖魔是什么找爱? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任梗顺,我火速辦了婚禮,結(jié)果婚禮上车摄,老公的妹妹穿的比我還像新娘寺谤。我一直安慰自己,他們只是感情好吮播,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布变屁。 她就那樣靜靜地躺著,像睡著了一般意狠。 火紅的嫁衣襯著肌膚如雪粟关。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天摄职,我揣著相機與錄音誊役,去河邊找鬼。 笑死谷市,一個胖子當(dāng)著我的面吹牛蛔垢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迫悠,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鹏漆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了创泄?” 一聲冷哼從身側(cè)響起艺玲,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鞠抑,沒想到半個月后饭聚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡搁拙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年秒梳,在試婚紗的時候發(fā)現(xiàn)自己被綠了法绵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡酪碘,死狀恐怖朋譬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兴垦,我是刑警寧澤徙赢,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站探越,受9級特大地震影響狡赐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扶关,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一阴汇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧节槐,春花似錦、人聲如沸拐纱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秸架。三九已至揍庄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間东抹,已是汗流浹背蚂子。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缭黔,地道東北人食茎。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像馏谨,于是被迫代替她去往敵國和親别渔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容