原文:https://mp.weixin.qq.com/s/gGR2itbY7hh9fo61SxaMQQ
文 / Google 開發(fā)者計劃工程師 Takeshi Hagikura
自從在去年的 Google I/O 大會上發(fā)布?ConstraintLayout?以來,我們一直不斷改進該布局的穩(wěn)定性抠艾,完善對布局編輯器的支持。我們還針對?ConstraintLayout?增加了一些新功能蛙酪,幫助您構建不同類型的布局滤否,例如引入鏈和按比例設置大小最仑。
除了這些功能之外,使用?ConstraintLayout?還可以獲得一項顯著的性能優(yōu)勢欲芹。在本文中菱父,我們將向您介紹如何從這些性能改進中獲益剑逃。
Android 如何繪制視圖蛹磺?
為了更好地理解?ConstraintLayout?的性能,我們先回過頭來看看 Android 如何繪制視圖裙品。
當用戶將某個 Android 視圖作為焦點時市怎,Android 框架會指示該視圖進行自我繪制区匠。這個繪制過程包括 3 個階段:
1. 測量
系統(tǒng)自頂向下遍歷視圖樹帅腌,以確定每個?ViewGroup?和 View 元素應當有多大。在測量?ViewGroup?的同時也會測量其子對象。
2. 布局
系統(tǒng)執(zhí)行另一個自頂向下的遍歷操作挽封,每個?ViewGroup?都根據(jù)測量階段中所確定的大小來確定其子對象的位置臣镣。
3. 繪制
系統(tǒng)再次執(zhí)行一個自頂向下的遍歷操作智亮。對于視圖樹中的每個對象点待,系統(tǒng)會為其創(chuàng)建一個?Canvas?對象,以便向 GPU 發(fā)送一個繪制命令列表状原。這些命令包含系統(tǒng)在前面 2 個階段中確定的?ViewGroup?和?View?對象的大小和位置苗踪。
▲測量階段如何遍歷視圖樹的示例
繪制過程中的每個階段都需要對視圖樹執(zhí)行一次自頂向下的遍歷操作毕莱。因此颅夺,視圖層次結構中嵌入(或嵌套)的視圖越多,設備繪制視圖所需的時間和計算功耗也就越多部服。通過在 Android 應用布局中保持扁平的層次結構稚字,您可以為應用創(chuàng)建響應快速而靈敏的界面胆描。
傳統(tǒng)布局層次結構的開銷
請牢記上述解釋,下面我們來創(chuàng)建一個使用?LinearLayout?和?RelativeLayout?對象的傳統(tǒng)布局層次結構国夜。
▲布局示例
假設我們想構建一個像上圖那樣的布局车吹。如果您使用傳統(tǒng)布局來構建窄驹,XML 文件會包含類似于下面這樣的元素層次結構(在本例中证逻,我們忽略屬性):
盡管一般來說,這種類型的視圖層次結構都有改進的空間瑞眼,但您幾乎必定還需要創(chuàng)建一個包含一些嵌套視圖的層次結構棵逊。
如前所述,嵌套的層次結構會給性能造成負面影響徒像。我們使用 Android Studio 的?Systrace?工具來看看嵌套視圖對界面性能到底有何實際影響厨姚。我們通過編程方式針對每個?ViewGroup(ConstraintLayout?和?RelativeLayout)調(diào)用了測量和布局階段并在執(zhí)行測量和布局調(diào)用期間觸發(fā)了 Systrace谬墙。以下命令可生成一個包含 20 秒間隔周期內(nèi)發(fā)生的關鍵 Event 的概覽文件经备,例如開銷巨大的測量/布局階段:
python $ANDROID_HOME/platform-tools/systrace/systrace.py --time=20 -o ~/trace.html gfx view res
有關如何使用 Systrace 的詳細信息侵蒙,請參閱使用 Systrace 分析界面性能指南:
https://developer.android.google.cn/studio/profile/systrace.html
Systrace 會自動突出顯示此布局中的(大量)性能問題,并給出修復這些問題的建議算凿。通過點擊“Alerts”標簽氓轰,您會發(fā)現(xiàn)浸卦,繪制此視圖層次結構需要反復執(zhí)行 80 次的測量和布局階段,開銷極為龐大靴庆!
觸發(fā)開銷如此龐大的測量和布局階段當然很不理想炉抒,如此龐大的繪制 Activity 會導致用戶能夠覺察到丟幀的現(xiàn)象端礼。我們可以得出這樣的結論:這種嵌套式層次結構和?RelativeLayout(會對其每個子對象重復測量兩次)的特性導致性能低下。
▲觀察 Systrace 針對使用?RelativeLayout?的布局版本發(fā)出的提醒
您可以在我們的?GitHub 代碼庫中查看我們用來執(zhí)行這些測量的完整代碼:
https://github.com/googlesamples/android-constraint-layout-performance
ConstraintLayout 對象的優(yōu)勢
如果您使用?ConstraintLayout?來構建相同的布局,XML 文件會包含類似于下面這樣的元素層次結構(再次忽略屬性):
如本例所示凡桥,現(xiàn)在,該布局擁有一個完全扁平的層次結構缅刽。這是因為?ConstraintLayout?允許您構建復雜的布局,而不必嵌套?View?和?ViewGroup?元素衰猛。
舉個例子啡省,我們來看一下布局中間的?TextView?和?EditText:
使用?RelativeLayout?時卦睹,您需要創(chuàng)建一個新的?ViewGroup?來垂直對齊?EditText?和 TextView:
? ? ? ? ? ? ? ?
android:layout_marginEnd="8dp" />? ?
通過改用?ConstraintLayout方库,您只需添加一個從?TextView?基線到?EditText?基線之間的約束纵潦,即可實現(xiàn)同樣的效果,而不必創(chuàng)建另一個?ViewGroup:
▲EditText 和 TextView 之間的約束
在針對我們使用?ConstraintLayout?的布局版本運行 Systrace 工具時返敬,您會發(fā)現(xiàn)救赐,同樣 20 秒間隔周期內(nèi)執(zhí)行的測量/布局次數(shù)大大減少只磷,開銷也隨之大大減少钮追。這種性能的改進很有意義,現(xiàn)在轧叽,我們保持了扁平的視圖層次結構!
▲觀察 Systrace 針對使用?ConstraintLayout?的布局版本發(fā)出的提醒
同樣值得一提的是待逞,我們構建?ConstraintLayout?版本的布局時僅僅使用了布局編輯器网严,而不是手工編輯 XML。而要使用?RelativeLayout?來實現(xiàn)同樣的視覺效果怜庸,我們很可能必須手工編輯 XML垢村。
測量性能差異
我們使用 Android 7.0(API 級別 24)中引入的?OnFrameMetricsAvailableListener?分析了?ConstraintLayout?和?RelativeLayout?這兩種類型的布局所執(zhí)行的每次測量和布局操作所花費的時間。通過該類宏榕,您可以收集有關應用界面渲染的逐幀時間信息担扑。
通過調(diào)用以下代碼,您可以開始記錄每個幀的界面操作:
window.addOnFrameMetricsAvailableListener(
frameMetricsAvailableListener, frameMetricsHandler);
在能夠獲取時間信息之后涌献,該應用觸發(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
測量結果:ConstraintLayout 速度更快
我們的性能比較結果表明:ConstraintLayout?在測量/布局階段的性能比?RelativeLayout大約高 40%:
▲測量/布局(單位:毫秒秦驯,100 幀的平均值)
這些結果表明:ConstraintLayout?很可能比傳統(tǒng)布局的性能更出色挣棕。不僅如此亲桥,ConstraintLayout?還具備其他一些功能题篷,能夠幫助您構建復雜的高性能布局悼凑。
有關詳情璧瞬,請參閱使用 ConstraintLayout 構建快速響應的界面指南:
https://medium.com/google-developers/building-interfaces-with-constraintlayout-3958fa38a9f7
我們建議您在設計應用布局時使用?ConstraintLayout嗤锉。在過去墓塌,幾乎所有情形下苫幢,您都需要一個深度嵌套的布局,因此韩肝,ConstraintLayout?應當成為您優(yōu)化性能和易用性的不二之選哀峻。
附錄:測量環(huán)境 &后續(xù)計劃
上述所有測量均在以下環(huán)境中執(zhí)行:
設備- ? ?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ā)送反饋。