View
物件階層的管理方式可能會對應用程式效能產生重大影響。本頁內容說明如何評估檢視區塊階層是否會導致應用程式速度變慢,並針對可能引起的問題提供解決策略。
版面配置和測量效能
轉譯管道包含「版面配置與測量」階段,在這個階段,系統會在檢視區塊階層中適當定位相關項目。此階段的測量部分會決定 View
物件的尺寸和界線,版面配置部分會決定 View
物件在畫面上的位置。
這兩個管道階段都會耗用少量處理檢視區塊或版面配置的資源。在大多數情況下,這個資源用量很低,對效能沒有明顯影響。但是,如果應用程式新增或移除 View 物件 (例如 RecyclerView
物件回收或重複使用這些物件),影響就可能會較大。假如 View
物件需要根據限制調整大小,耗用的資源也可能比較多:舉例來說,如果應用程式對會將文字自動換行的 View
物件呼叫 SetText()
,View
就可能需要調整大小。
如果這類情況所需時間過長,影格就可能無法在 16 毫秒的允許時間內顯示,進而導致多個影格遭到捨棄,動畫也會出現卡頓情形。
由於無法將這些作業移至背景工作執行緒 (應用程式必須在主執行緒上進行處理),最好的解決方式是進行最佳化調整,盡可能縮短所需時間。
管理複雜性:版面配置事項
您可以利用 Android Layouts 在檢視區塊階層中建立巢狀結構的 UI 物件。這個巢狀結構也可能會耗用版面配置的資源。應用程式處理版面配置的物件時,也會對該版面配置的所有子項執行相同程序。如果是複雜的版面配置,有時只有在系統第一次計算版面配置時才會耗用資源。例如當應用程式回收 RecyclerView
物件中的某個複雜清單項目時,系統就需要安排所有物件的位置。在另一個範例中,細小的變更可能會向上傳播到鏈結中的父項,直到碰觸到不會影響父項尺寸的物件為止。
版面配置花費特別長時間的最常見情況,是多個階層的 View
物件構成彼此互嵌的巢狀結構。每個巢狀版面配置物件都會增加版面配置階段的耗用資源。階層越簡單,完成版面配置階段所需的時間就越短。
如果使用 RelativeLayout
類別,也許可以改為使用巢狀的輕量 LinearLayout
檢視區塊來達到相同效果,而且耗用資源較少。此外,如果應用程式指定 Android 7.0 (API 級別 24),您可能可以使用特殊的版面配置編輯器來建立 ConstraintLayout
物件,而不是 RelativeLayout
。這樣做可以避免發生本節所述的許多問題。ConstraintLayout
類別提供類似的版面配置控制項,但可大幅提升效能。這個類別會使用專屬的限制解決系統,以與標準版面配置截然不同的方式解析檢視區塊間的關係。
重複作業
一般來說,架構會在單次傳遞中執行版面配置或測量階段,而且相當快速。然而,在某些較複雜的版面配置情況中,對於需要數度傳遞才能解析的階層部分,架構可能要多次疊代才能安排元素的最終位置。這種必須執行多次版面配置和測量疊代的情形,稱為「重複作業」。
舉例來說,使用 RelativeLayout
容器時,因為此容器可讓您依照其他 View
物件的位置,相對放置 View
物件,架構會執行以下動作:
- 執行版面配置和測量傳遞,架構會在此期間根據各子項的要求,計算每個子項物件的位置和尺寸。
- 使用這項資料,並將物件粗細納入考量,算出相關檢視區塊的正確位置。
- 執行第二次版面配置傳遞,確定物件的位置。
- 繼續進行轉譯程序的下一階段。
檢視區塊階層的層級越多,對效能的負面影響就越大。
RelativeLayout
以外的容器也可能引起重複作業。例如:
- 如果將
LinearLayout
檢視區塊水平放置,就可能導致兩次的版面配置和測量傳遞。如果在垂直方向加入 measureWithLargestChild,架構可能需要執行第二次傳遞來解析物件的正確尺寸,因此也可能發生兩次的版面配置和測量傳遞。 GridLayout
也會引起類似問題。雖然這個容器也允許相對定位,但會預先處理子項檢視區塊之間的位置關係,因此通常可以避免發生重複作業。不過,如果版面配置使用Gravity
類別加入線條粗細或填色,就會失去預先處理的優勢,而在容器為RelativeLayout
的情況下,架構可能必須執行多次傳遞。
多次版面配置和測量傳遞本身並不會造成效能上的負擔。但如果發生在錯誤的位置,就可能會降低效能。容器符合以下任一種情況時,請務必謹慎處理:
- 容器是檢視區塊階層的根元素。
- 容器底下的檢視區塊階層較深。
- 畫面會填入容器的多個例項,類似
ListView
物件中的子項。
診斷檢視區塊階層的問題
版面配置效能是包含多個面向的複雜問題。您可以透過多種工具取得具體的指標,確實掌握效能瓶頸的所在位置。少數其他工具提供的資訊較不明確,但也能提供實用提示。
Systrace
Android SDK 內建的 Systrace 是提供效能相關優質資料的工具。您可以利用 Systrace 工具收集及檢查整部 Android 裝置的時間資訊,瞭解版面配置問題導致發生效能問題的時間。如要進一步瞭解 Systrace,請參閱「系統追蹤總覽」一文。
剖析 GPU 轉譯
另一項最可能提供效能瓶頸具體資訊的是裝置端剖析 GPU 轉譯工具,搭載 Android 6.0 (API 級別 23) 以上版本的裝置均提供這項工具。您可以利用這項工具,瞭解在版面配置和測量階段為每個影格花費的轉譯時間。這項資料有助於診斷執行階段效能問題,以及判斷是否有哪些版面配置和測量問題需要解決。
剖析 GPU 轉譯會以圖形呈現擷取的資料,在其中使用藍色表示版面配置時間。如要進一步瞭解如何使用這項工具,請參閱剖析 GPU 轉譯逐步操作說明。
Lint
Android Studio 的 Lint 工具可協助您發掘檢視區塊階層中效率不佳的問題。如要使用這項工具,請依序選取「Analyze」>「Inspect Code」,如圖 1 所示。

圖 1在 Android Studio 中找出「Inspect Code」。
在「Android」>「Lint」>「Performance」下方會顯示多個版面配置項目的資訊。如要瞭解細節,請點選展開各個項目,在畫面右側的窗格中查看詳細資訊。圖 2 顯示這類畫面的範例。

圖 2查看 Lint 工具找出的特定問題相關資訊。
點選其中一個項目,即可在右側窗格中顯示該項目的相關問題。
如要進一步瞭解這部分的特定主題和問題,請參閱 Lint 說明文件。
版面配置檢查器
Android Studio 的版面配置檢查器工具提供應用程式的檢視區塊階層示意圖。 這是瀏覽應用程式階層的好方法,您可以透過清楚的圖表查看特定檢視區塊的父項鏈結,便於檢查應用程式建構的版面配置。
您也可以透過版面配置檢查器顯示的檢視區塊,找出重複作業造成的效能問題。您也可以用這種方式輕鬆識別巢狀版面配置的深層鏈結,或是具有大量巢狀子項的版面配置區域,這是另一個可能耗用資源、影響效能的來源。在這類情況下,版面配置和測量階段可能會特別耗用資源,造成效能問題。
詳情請參閱「使用版面配置檢查器對版面配置偵錯」一文。
解決檢視區塊階層的問題
要解決檢視區塊階層所引起的效能問題,背後的基本概念雖然簡單,在實務上卻較為困難。要防止檢視區塊階層導致效能降低,需要同時達成兩個目標,分別是簡化檢視區塊階層和減少重複作業。本節會說明幾項有助達成這些目標的策略。
移除多餘的巢狀版面配置
開發人員經常會使用過多的巢狀版面配置。舉例來說,RelativeLayout
容器包含的單一子項可能也是 RelativeLayout
容器。這樣的巢狀結構是多餘的,會為檢視區塊階層增加不必要的資源浪費。
Lint 通常可以標記這個問題,減少偵錯所需時間。
採用 merge/include 標記
使用多冗餘巢狀版面配置的其中一個原因就是 <include> 標記。 舉例來說,您可以定義可重複使用的版面配置,如下所示:
<LinearLayout> <!-- some stuff here --> </LinearLayout>
接著加入標記,將此項目加入父項容器:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/app_bg" android:gravity="center_horizontal"> <include layout="@layout/titlebar"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello" android:padding="10dp" /> ... </LinearLayout>
這個 include 標記非必要地將第一個版面配置嵌入第二個版面配置內,建立巢狀結構。
合併標記有助於避免這個問題。如需此標記的相關資訊,請參閱「利用 <include> 重複使用版面配置」。
採用成本較低的版面配置
您可能無法調整現有的版面配置設定,移除多餘的版面配置。在某些情況下,唯一的解決方式可能是改用完全不同的版面配置類型,從而簡化階層。
舉例來說,您可能會發現 TableLayout
提供的功能,與含有許多位置依附元件的複雜版面配置相同。在 Android N 版本中,ConstraintLayout
類別提供的功能類似於 RelativeLayout
,卻能大幅減少耗用資源。