了解使用 ConstraintLayout 的性能優(yōu)勢

原文:谷歌開發(fā)者中文博客
了解使用 ConstraintLayout 的性能優(yōu)勢

發(fā)布人:開發(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)自頂向下遍歷視圖樹秽梅,以確定每個ViewGroupView元素應(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 個階段中確定的ViewGroupView對象的大小和位置褥实。

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

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

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

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

圖 2. 布局示例

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

<RelativeLayout>
   <ImageView /> 
   <ImageView /> 
   <RelativeLayout> 
      <TextView /> 
      <LinearLayout> 
         <TextView /> 
         <RelativeLayout> 
            <EditText /> 
         </RelativeLayout> 
      </LinearLayout> 
      <LinearLayout>
         <TextView /> 
         <RelativeLayout> 
            <EditText /> 
         </RelativeLayout> 
      </LinearLayout> 
      <TextView /> 
   </RelativeLayout> 
   <LinearLayout > 
      <Button /> 
      <Button /> 
   </LinearLayout>
</RelativeLayout>

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

如前所述,嵌套的層次結(jié)構(gòu)會給性能造成負(fù)面影響哎壳。我們使用 Android Studio 的 Systrace 工具來看看嵌套視圖對界面性能到底有何實際影響墨礁。我們通過編程方式針對每個ViewGroupConstraintLayoutRelativeLayout)調(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 的詳細(xì)信息,請參閱使用 Systrace 分析界面性能指南焕毫。

Systrace 會自動突出顯示此布局中的(大量)性能問題蹲坷,并給出修復(fù)這些問題的建議。通過點擊“Alerts”標(biāo)簽邑飒,您會發(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)致性能低下撒轮。

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

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

ConstraintLayout 對象的優(yōu)勢

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

<android.support.constraint.ConstraintLayout> 
   <ImageView />
   <ImageView />
   <TextView />
   <EditText />
   <TextView />
   <TextView />
   <EditText />
   <Button />
   <Button />
   <TextView />
</android.support.constraint.ConstraintLayout>

如本例所示题山,現(xiàn)在兰粉,該布局擁有一個完全扁平的層次結(jié)構(gòu)。這是因為ConstraintLayout允許您構(gòu)建復(fù)雜的布局顶瞳,而不必嵌套ViewViewGroup元素玖姑。

舉個例子,我們來看一下布局中間的TextViewEditText


使用RelativeLayout時慨菱,您需要創(chuàng)建一個新的ViewGroup來垂直對齊EditTextTextView

<LinearLayout 
   android:id="@+id/camera_area" 
   android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   android:orientation="horizontal" 
   android:layout_below="@id/title" > 
      <TextView 
         android:text="@string/camera" 
         android:layout_width="wrap_content"       
         android:layout_height="wrap_content" 
         android:layout_gravity="center_vertical" 
         android:id="@+id/cameraLabel" 
         android:labelFor="@+id/cameraType"
         android:layout_marginStart="16dp" /> 
      <RelativeLayout 
         android:layout_width="match_parent" 
         android:layout_height="wrap_content"> 
         <EditText 
            android:id="@+id/cameraType" 
            android:ems="10" 
            android:inputType="textPersonName"       
            android:text="@string/camera_value" 
            android:layout_width="match_parent" 
            android:layout_height="wrap_content" 
            android:layout_centerVertical="true" 
            android:layout_marginTop="8dp" 
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp" /> 
      </RelativeLayout>
</LinearLayout>

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

圖 4. EditText 和 TextView 之間的約束

<TextView 
   android:layout_width="wrap_content" 
   android:layout_height="wrap_content" 
   app:layout_constraintLeft_creator="1" 
   app:layout_constraintBaseline_creator="1" 
   app:layout_constraintLeft_toLeftOf="@+id/activity_main_done" 
   app:layout_constraintBaseline_toBaselineOf="@+id/cameraType" />

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

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

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

測量性能差異

我們使用 Android 7.0(API 級別 24)中引入的 OnFrameMetricsAvailableListener 分析了ConstraintLayoutRelativeLayout這兩種類型的布局所執(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);

如需詳細(xì)了解FrameMetrics可以檢索的其他類型的持續(xù)時間信息嫂丙,請參閱 FrameMetrics
API 參考娘赴。

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

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

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

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

附錄:測量環(huán)境

1 2
設(shè)備 Nexus 5X
Android 版本 8.0
ConstraintLayout 版本 1.0.2

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

后續(xù)計劃

查看[開發(fā)者指南](https://developer.android.google.cn/training/c
onstraint-layout/index.html)、API 參考文檔媒體文章莹规,以完全理解ConstraintLayout能夠給您帶來什么赔蒲。再次感謝您,感謝自從我們的 Alpha 版ConstraintLayout發(fā)布以來的幾個月里提交反饋和問題的所有同仁良漱。我們得以在今年早些時候發(fā)布ConstraintLayout 1.0 正式版舞虱,離不開您的支持,我們在此謹(jǐn)致以誠摯的謝意母市!我們將繼續(xù)改進ConstraintLayout矾兜,請您繼續(xù)使用 Android Issue Tracker 向我們發(fā)送反饋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末患久,一起剝皮案震驚了整個濱河市椅寺,隨后出現(xiàn)的幾起案子浑槽,更是在濱河造成了極大的恐慌,老刑警劉巖返帕,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桐玻,死亡現(xiàn)場離奇詭異,居然都是意外死亡荆萤,警方通過查閱死者的電腦和手機镊靴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來链韭,“玉大人偏竟,你說我怎么就攤上這事∥嘤停” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵州邢,是天一觀的道長儡陨。 經(jīng)常有香客問我,道長量淌,這世上最難降的妖魔是什么骗村? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮呀枢,結(jié)果婚禮上胚股,老公的妹妹穿的比我還像新娘。我一直安慰自己裙秋,他們只是感情好琅拌,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摘刑,像睡著了一般进宝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枷恕,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天党晋,我揣著相機與錄音,去河邊找鬼徐块。 笑死未玻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胡控。 我是一名探鬼主播扳剿,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昼激!你這毒婦竟也來了舞终?” 一聲冷哼從身側(cè)響起轻庆,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敛劝,沒想到半個月后余爆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡夸盟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年蛾方,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片上陕。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡桩砰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出释簿,到底是詐尸還是另有隱情亚隅,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布庶溶,位于F島的核電站煮纵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏偏螺。R本人自食惡果不足惜行疏,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望套像。 院中可真熱鬧酿联,春花似錦、人聲如沸夺巩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柳譬。三九已至震桶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間征绎,已是汗流浹背蹲姐。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留人柿,地道東北人柴墩。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像凫岖,于是被迫代替她去往敵國和親江咳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

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