了解使用 ConstraintLayout 的性能優(yōu)勢(shì)(轉(zhuǎn))

發(fā)布人:開發(fā)者計(jì)劃工程師 Takeshi Hagikura

自從在去年的 Google I/O 大會(huì)上發(fā)布ConstraintLayout以來(lái),我們一直不斷改進(jìn)該布局的穩(wěn)定性,完善對(duì)布局編輯器的支持。我們還針對(duì)ConstraintLayout增加了一些新功能,幫助您構(gòu)建不同類型的布局,例如引入鏈按比例設(shè)置大小。除了這些功能之外,使用ConstraintLayout還可以獲得一項(xiàng)顯著的性能優(yōu)勢(shì)。在本博文中,我們將向您介紹如何從這些性能改進(jìn)中獲益。

Android 如何繪制視圖?

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

當(dāng)用戶將某個(gè) Android 視圖作為焦點(diǎn)時(shí),Android 框架會(huì)指示該視圖進(jìn)行自我繪制。這個(gè)繪制過程包括 3 個(gè)階段:

測(cè)量

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

布局

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

繪制

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

圖 1.測(cè)量階段如何遍歷視圖樹的示例

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

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

請(qǐng)牢記上述解釋,下面我們來(lái)創(chuàng)建一個(gè)使用LinearLayout和RelativeLayout對(duì)象的傳統(tǒng)布局層次結(jié)構(gòu)。

? ? ? 圖 2.布局示例

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

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

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

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

有關(guān)如何使用 Systrace 的詳細(xì)信息,請(qǐng)參閱使用 Systrace 分析界面性能指南。

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

觸發(fā)開銷如此龐大的測(cè)量和布局階段當(dāng)然很不理想,如此龐大的繪制 Activity 會(huì)導(dǎo)致用戶能夠覺察到丟幀的現(xiàn)象。我們可以得出這樣的結(jié)論:這種嵌套式層次結(jié)構(gòu)和RelativeLayout(會(huì)對(duì)其每個(gè)子對(duì)象重復(fù)測(cè)量?jī)纱危?a href="http://www.itdecent.cn/p/8a7d059da746" target="_blank">原因請(qǐng)參考))的特性導(dǎo)致性能低下。

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

您可以在我們的GitHub 代碼庫(kù)中查看我們用來(lái)執(zhí)行這些測(cè)量的完整代碼。

ConstraintLayout 對(duì)象的優(yōu)勢(shì)

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

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

舉個(gè)例子,我們來(lái)看一下布局中間的TextView和EditText:

使用RelativeLayout時(shí),您需要?jiǎng)?chuàng)建一個(gè)新的ViewGroup來(lái)垂直對(duì)齊EditText和 TextView:

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

圖 4.EditText 和 TextView 之間的約束

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

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

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

測(cè)量性能差異

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

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

在能夠獲取時(shí)間信息之后,該應(yīng)用觸發(fā)frameMetricsAvailableListener()回調(diào)。我們對(duì)測(cè)量/布局的性能感興趣,因此,我們?cè)跈z索實(shí)際幀的持續(xù)時(shí)間時(shí)調(diào)用了FrameMetrics.LAYOUT_MEASURE_DURATION。

如需詳細(xì)了解FrameMetrics可以檢索的其他類型的持續(xù)時(shí)間信息,請(qǐng)參閱FrameMetricsAPI 參考。

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

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

圖 6.測(cè)量/布局(單位:毫秒,100 幀的平均值)

這些結(jié)果表明:ConstraintLayout很可能比傳統(tǒng)布局的性能更出色。不僅如此,正如ConstraintLayout 對(duì)象的優(yōu)勢(shì)一節(jié)中所介紹的那樣,ConstraintLayout還具備其他一些功能,能夠幫助您構(gòu)建復(fù)雜的高性能布局。有關(guān)詳情,請(qǐng)參閱使用 ConstraintLayout 構(gòu)建快速響應(yīng)的界面指南。我們建議您在設(shè)計(jì)應(yīng)用布局時(shí)使用ConstraintLayout。在過去,幾乎所有情形下,您都需要一個(gè)深度嵌套的布局,因此,ConstraintLayout應(yīng)當(dāng)成為您優(yōu)化性能和易用性的不二之選。

測(cè)試環(huán)境

后續(xù)計(jì)劃

查看開發(fā)者指南、API 參考文檔媒體文章,以完全理解ConstraintLayout能夠給您帶來(lái)什么。再次感謝您,感謝自從我們的 Alpha 版ConstraintLayout發(fā)布以來(lái)的幾個(gè)月里提交反饋和問題的所有同仁。我們得以在今年早些時(shí)候發(fā)布ConstraintLayout的1.0 正式版,離不開您的支持,我們?cè)诖酥?jǐn)致以誠(chéng)摯的謝意!我們將繼續(xù)改進(jìn)ConstraintLayout,請(qǐng)您繼續(xù)使用Android Issue Tracker向我們發(fā)送反饋。

個(gè)人學(xué)習(xí)ConstraintLayout中參考資料:

英文:https://constraintlayout.github.io/basics/

中文:https://biaomingzhong.github.io/

有問題請(qǐng)留言溝通。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容