Android應(yīng)用界面優(yōu)化

界面是 Android 應(yīng)用中直接影響用戶體驗(yàn)最關(guān)鍵的部分箱舞。如果代碼實(shí)現(xiàn)得不好贮折,界面容易發(fā)生卡頓且導(dǎo)致應(yīng)用占用大量?jī)?nèi)存裤翩。

目錄

一. Android渲染知識(shí)

1.1 繪制原理

1.2 掉幀

1.3 為什么是60Fps?

1.4 垃圾回收

1.5 UI 線程

1.6 垂直同步

1.7 UI 繪制機(jī)制與柵格化

二. 檢測(cè)和解決

2.1 檢測(cè)維度

2.2 調(diào)試工具

2.3 如何解決

三. 界面過度繪制

3.1 過度繪制概念

3.2 追蹤過度繪制

3.3 過度繪制的根源

3.4 不合理的xml布局對(duì)繪制的影響

3.5 源碼相關(guān)

四. 渲染性能

4.1 渲染性能概念

4.2 追蹤渲染性能

4.3 渲染性能差的根源

4.4 檢測(cè)說明

4.5 UI繪制機(jī)制的補(bǔ)充說明

五. 布局邊界合理性

六. 給開發(fā)的界面優(yōu)化建議

6.1 優(yōu)化布局的結(jié)構(gòu)

6.2 優(yōu)化處理邏輯

6.3 善用 DEBUG 工具

一. Android渲染知識(shí)

1.1 繪制原理

    Android系統(tǒng)要求每一幀都要在 16ms 內(nèi)繪制完成调榄,平滑的完成一幀意味著任何特殊的幀需要執(zhí)行所有的渲染代碼(包括 framework 發(fā)送給 GPU 和 CPU 繪制到緩沖區(qū)的命令)都要在 16ms 內(nèi)完成踊赠,保持流暢的體驗(yàn)。這個(gè)速度允許系統(tǒng)在動(dòng)畫和輸入事件的過程中以約 60 幀每秒( 1秒 / 0.016幀每秒 = 62.5幀/秒 )的平滑幀率來(lái)渲染每庆。
image
    如果你的應(yīng)用沒有在 16ms 內(nèi)完成這一幀的繪制筐带,假設(shè)你花了 24ms 來(lái)繪制這一幀,那么就會(huì)出現(xiàn)掉幀的情況缤灵。
image
    系統(tǒng)準(zhǔn)備將新的一幀繪制到屏幕上伦籍,但是這一幀并沒有準(zhǔn)備好,所有就不會(huì)有繪制操作腮出,畫面也就不會(huì)刷新帖鸦。反饋到用戶身上,就是用戶盯著同一張圖看了 32ms 而不是 16ms 胚嘲,也就是說掉幀發(fā)生了作儿。

1.2 掉幀

    掉幀是用戶體驗(yàn)中一個(gè)非常核心的問題。丟棄了當(dāng)前幀馋劈,并且之后不能夠延續(xù)之前的幀率攻锰,這種不連續(xù)的間隔會(huì)容易會(huì)引起用戶的注意,也就是我們常說的卡頓妓雾、不流暢娶吞。

    引起掉幀的原因非常多,比如:

花了非常多時(shí)間重新繪制界面中的大部分東西君珠,這樣非常浪費(fèi)CPU周期寝志;

過度繪制嚴(yán)重,在繪制用戶看不到的對(duì)象上花費(fèi)了太多的時(shí)間策添;

有一大堆動(dòng)畫重復(fù)了一遍又一遍材部,消耗 CPU 、 GPU 資源唯竹;

頻繁的觸發(fā)垃圾回收乐导;

1.3 為什么是60Fps?

    Android系統(tǒng)要求每一幀都要在 16ms 內(nèi)繪制完成浸颓,那么1秒的幀率就是約 60 幀每秒( 1秒 / 0.016幀每秒 = 62.5幀/秒 )物臂,那為什么要以 60 Fps來(lái)作為 App 性能的衡量標(biāo)準(zhǔn)呢旺拉?這是因?yàn)槿搜酆痛竽X之間的協(xié)作無(wú)法感知到超過 60 Fps的畫面更新。

    市面上絕大多數(shù)Android設(shè)備的屏幕刷新頻率是 60 HZ棵磷。當(dāng)然蛾狗,超過 60 Fps 是沒有意義的,人眼感知不到區(qū)別仪媒。24 Fps 是人眼能感知的連續(xù)線性的運(yùn)動(dòng)沉桌,所以是電影膠圈的常用幀率,因?yàn)檫@個(gè)幀率已經(jīng)足夠支撐大部分電影畫面所要表達(dá)的內(nèi)容算吩,同時(shí)能最大限度地減少費(fèi)用支出留凭。但是,低于 30 Fps 是無(wú)法順暢表現(xiàn)絢麗的畫面內(nèi)容的偎巢,此時(shí)就需要用到 60 Fps 來(lái)達(dá)到想要表達(dá)的效果蔼夜。了解更多Fps知識(shí)詳見「 Wiki 」。

    應(yīng)用的界面性能目標(biāo)就是保持 60 Fps压昼,這意味著每一幀你只有 16 ms(1秒 / 60幀率)的時(shí)間來(lái)處理所有的任務(wù)求冷。

1.4 垃圾回收

    垃圾回收器是一個(gè)在應(yīng)用運(yùn)行期間自動(dòng)釋放那些不再引用的內(nèi)存的機(jī)制,常稱 GC 巢音。頻繁的 GC 也是導(dǎo)致嚴(yán)重性能問題的罪魁禍?zhǔn)字弧?
    前面提到遵倦,平滑的完成一幀意味著所有渲染代碼都必須在 16ms 內(nèi)完成。頻繁的 GC 會(huì)嚴(yán)重限制一幀時(shí)間內(nèi)的剩余時(shí)間官撼,如果 GC 所做的工作超過了那些必須的工作,那么留給應(yīng)用平滑的幀率的時(shí)間就越少似谁。越接近 16ms 傲绣,在垃圾回收事件觸發(fā)的時(shí)候,就越容易導(dǎo)致卡頓巩踏。

    注意秃诵,Android4.4 引進(jìn)了新的 ART 虛擬機(jī)來(lái)取代 Dalvik 虛擬機(jī)。它們的機(jī)制大有不同塞琼,簡(jiǎn)單而言:

Dalvik 虛擬機(jī)的 GC 是非常耗資源的菠净,并且在正常的情況下一個(gè)硬件性能不錯(cuò)的Android設(shè)備也會(huì)很容易耗費(fèi)掉 10 – 20 ms 的時(shí)間;

ART 虛擬機(jī)的GC會(huì)動(dòng)態(tài)提升垃圾回收的效率彪杉,在 ART 中的中斷毅往,通常在 2 – 3 ms 間。 比 Dalvik 虛擬機(jī)有很大的性能提升派近;

    ART 虛擬機(jī)相對(duì)于 Dalvik 虛擬機(jī)來(lái)說的垃圾回收來(lái)說有一個(gè)很大的性能提升攀唯,但 2 – 3 ms 的回收時(shí)間對(duì)于超過16ms幀率的界限也是足夠的。因此渴丸,盡管垃圾回收在 Android 5.0 之后不再是耗資源的行為褐啡,但也是始終需要盡可能避免的,特別是在執(zhí)行動(dòng)畫的情況下汁汗,可能會(huì)導(dǎo)致一些讓用戶明顯感覺的丟幀有梆。

1.5 UI 線程

    UI 線程是應(yīng)用的主線程,很多的性能和卡頓問題是由于我們?cè)谥骶€程中做了大量的工作诵姜。

    所以,所有耗資源的操作,比如 IO 操作囊卜、網(wǎng)絡(luò)操作、SQL 操作错沃、列表刷新等栅组,都應(yīng)該用后臺(tái)進(jìn)程去實(shí)現(xiàn),不能占用主線程枢析,主線程是 UI 線程玉掸,是保持程序流暢的關(guān)鍵;

    在 Android 5.0 版本里醒叁,Android 框架層引入了 “ Render Thread ” 司浪,用于向 GPU 發(fā)送實(shí)際渲染的操作。這個(gè)線程減輕了一些 UI 線程減少的操作把沼。但是輸入啊易、滾動(dòng)和動(dòng)畫仍然在 UI thread,因?yàn)?Thread 必須能夠響應(yīng)操作饮睬。

1.6 垂直同步

    垂直同步是 Android4.1 通過 Project Butter 在 UI 架構(gòu)中引入的新技術(shù)租谈,同期引入的還有 Triple Buffer 和 HWComposer 等技術(shù),都是為提高 UI 的流暢性而生捆愁。

    舉個(gè)例子割去,你拍了一張照片,然后旋轉(zhuǎn)5度再拍另外一張照片昼丑,將兩照片的中間剪開并拼接在一起呻逆,得到下圖:

    中間這部分有明顯區(qū)別的部分,等價(jià)于設(shè)備刷新率和幀速率不一致的結(jié)果菩帝。

    一般而言咖城, GPU 的幀速率應(yīng)高于刷新率,才不會(huì)卡頓或掉幀呼奢。如果屏幕刷新率比幀速率還快宜雀,屏幕會(huì)在兩幀中顯示同一個(gè)畫面,這種斷斷續(xù)續(xù)情況持續(xù)發(fā)生時(shí)控妻,用戶將會(huì)很明顯地感覺到動(dòng)畫的卡頓或者掉幀州袒,然后又恢復(fù)正常,我們常稱之為閃屏弓候、跳幀郎哭、延遲他匪。

    應(yīng)用應(yīng)避免這些幀率下降的情況,以確保 GPU 能在屏幕刷新之前完成數(shù)據(jù)的獲取及寫入夸研,保證動(dòng)畫流暢邦蜜。

1.7 UI 繪制機(jī)制與柵格化

    絕大多數(shù)渲染操作都依賴兩個(gè)硬件: CPU 、 GPU 亥至。 CPU 負(fù)責(zé) Measure 悼沈、 layout 、 Record 姐扮、 Execute 的計(jì)算操作絮供, GPU 負(fù)責(zé)柵格化( Rasterization )操作。 非必需的視圖組件會(huì)帶來(lái)多余的 CPU 計(jì)算操作茶敏,還會(huì)占用多余的 GPU 資源壤靶。

    柵格化( Rasterization )能將 Button 、 Shape 惊搏、 Path 贮乳、 Bitmap 等資源組件拆分到不同的像素上進(jìn)行顯示。這個(gè)操作很費(fèi)時(shí)恬惯,所以引入了 GPU 來(lái)加快柵格化的操作向拆。

CPU 負(fù)責(zé)把 UI 組件計(jì)算成多邊形( Polygons ),紋理( Texture )酪耳,然后交給 GPU 進(jìn)行柵格化渲染浓恳,再將處理結(jié)果傳到屏幕上顯示。

    在 Android 里的那些資源組件的顯示(比如 Bitmaps 葡兑、 Drawable )奖蔓,都是一起打包到統(tǒng)一的紋理( Texture )當(dāng)中,然后再傳遞到 GPU 里面讹堤。

    圖片的顯示,則是先經(jīng)過 CPU 的計(jì)算加載到內(nèi)存中厨疙,再傳給 GPU 進(jìn)行渲染洲守。

文字的顯示,則是先經(jīng)過 CPU 換算成紋理( Texture )沾凄,再傳給 GPU 進(jìn)行渲染梗醇,返回到 CPU 繪制單個(gè)字符的時(shí)候,再重新引用經(jīng)過 GPU 渲染的內(nèi)容撒蟀。

    動(dòng)畫的顯示更加復(fù)雜叙谨,我們需要在 16 ms 內(nèi)處理完所有 CPU 和 GPU 的計(jì)算、繪制保屯、渲染等操作手负,才能獲得應(yīng)用的流暢體驗(yàn)涤垫。

二. To檢測(cè)和解決

2.1 檢測(cè)維度

    根據(jù)業(yè)務(wù)的不同與所需要的測(cè)試粒度的不同,就會(huì)有不同的檢測(cè)維度竟终。目前我所在業(yè)務(wù)所需的界面性能檢測(cè)維度如下:

界面過度繪制蝠猬;(檢測(cè)過度繪制)

渲染性能;(檢測(cè)嚴(yán)格模式下的UI渲染性能呈現(xiàn))

布局邊界合理性统捶;(檢測(cè)元素顯示的合理性)

    還有專項(xiàng)測(cè)試中某些用戶場(chǎng)景可能還包含著另外一些隱形的檢測(cè)維度榆芦,比如:

OpenGL 跟蹤分析;

GPU 視圖更新合理性喘鸟;

Flash 硬件層更新合理性匆绣;

動(dòng)畫加 / 減速狀態(tài)問題點(diǎn)檢測(cè);

……

2.2 調(diào)試工具

    檢測(cè)和解決界面性能問題很大程度上依賴于你的應(yīng)用程序架構(gòu)什黑,幸運(yùn)的是崎淳,Andorid 提供了很多調(diào)試工具,知道并學(xué)會(huì)使用這些工具很重要兑凿,它們可以幫助我們調(diào)試和分析界面性能問題凯力,以讓應(yīng)用擁有更好的性能體驗(yàn)。下面列舉Android常見的界面性能調(diào)試工具:

2.2.1 Hierarchy View

    Hierarchy View 在Android SDK里自帶礼华,常用來(lái)查看界面的視圖結(jié)構(gòu)是否過于復(fù)雜咐鹤,用于了解哪些視圖過度繪制,又該如何進(jìn)行改進(jìn)圣絮。詳見官方使用教程(需要翻墻):「 戳我 」祈惶,官方介紹「 戳我 」。

2.2.2 Lint

    Lint 是 ADT 自帶的靜態(tài)代碼掃描工具扮匠,可以給 XML 布局文件和 項(xiàng)目代碼中不合理的或存在風(fēng)險(xiǎn)的模塊提出改善性建議捧请。官方關(guān)于 Lint 的實(shí)際使用的提示,列舉幾點(diǎn)如下:

包含無(wú)用的分支棒搜,建議去除疹蛉;

包含無(wú)用的父控件,建議去除力麸;

警告該布局深度過深可款;

建議使用 compound drawables ;

建議使用 merge 標(biāo)簽克蚂;

……

2.2.3 Systrace

    Systrace 在Android DDMS 里自帶闺鲸,可以用來(lái)跟蹤 graphics 、view 和 window 的信息埃叭,發(fā)現(xiàn)一些深層次的問題摸恍。很麻煩,限制大赤屋,實(shí)際調(diào)試中我基本用不到立镶。官方介紹 「戳我」和 「我」壁袄。

2.2.4 Track

    Track 在 Android DDMS里自帶,是個(gè)很棒的用來(lái)跟蹤構(gòu)造視圖的時(shí)候哪些方法費(fèi)時(shí)谜慌,精確到每一個(gè)函數(shù)然想,無(wú)論是應(yīng)用函數(shù)還是系統(tǒng)函數(shù),我們可以很容易地看到掉幀的地方以及那一幀所有函數(shù)的調(diào)用情況欣范,找出問題點(diǎn)進(jìn)行優(yōu)化变泄。官方介紹 「戳我」。

2.2.5 OverDraw

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里打開 “ 調(diào)試 GPU 過度繪制 ” 恼琼,來(lái)查看應(yīng)用所有界面及分支界面下的過度繪制情況妨蛹,方便進(jìn)行優(yōu)化。官方介紹 「戳我」晴竞。

2.2.6 GPU 呈現(xiàn)模式分析

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里啟動(dòng) “ GPU 呈現(xiàn)模式分析 ” 蛙卤,可以得到最近 128 幀 每一幀渲染的時(shí)間,分析性能渲染的性能及性能瓶頸噩死。官方介紹 「戳我」颤难。

2.2.7 StrictMode

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里啟動(dòng) “ 嚴(yán)格模式 ” ,來(lái)查看應(yīng)用哪些操作在主線程上執(zhí)行時(shí)間過長(zhǎng)已维。當(dāng)一些操作違背了嚴(yán)格模式時(shí)屏幕的四周邊界會(huì)閃爍紅色行嗤,同時(shí)輸出 StrictMode 的相關(guān)信息到 LOGCAT 日志中。

2.2.8 Animator duration scale

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里打開 “ 窗口動(dòng)畫縮放 ” / “ 過渡動(dòng)畫縮放 ” / “ 動(dòng)畫程序時(shí)長(zhǎng)縮放 ”垛耳,來(lái)加速或減慢動(dòng)畫的時(shí)間栅屏,以查看加速或減慢狀態(tài)下的動(dòng)畫是否會(huì)有問題。

2.2.9 Show hardware layer updates

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里啟動(dòng) “ 顯示硬件層更新 ”堂鲜,當(dāng) Flash 硬件層在進(jìn)行更新時(shí)會(huì)顯示為綠色栈雳。使用這個(gè)工具可以讓你查看在動(dòng)畫期間哪些不期望更新的布局有更新,方便你進(jìn)行優(yōu)化缔莲,以獲得應(yīng)用更好的性能哥纫。實(shí)例《 Optimizing Android Hardware Layers 》(需要翻墻):「 戳我 」。

2.3 如何解決

    前面提到過我司的目前所需的測(cè)試維度如下:

界面過度繪制痴奏;(檢測(cè)過度繪制)

渲染性能磺箕;(檢測(cè)嚴(yán)格模式下的UI渲染性能呈現(xiàn))

布局邊界合理性;(檢測(cè)元素顯示的合理性)

    故接下來(lái)將圍繞這三兩點(diǎn)抛虫,分別從概念、追蹤简僧、挖掘根源以及排查的工具來(lái)具體講述如何解決建椰,以及給開發(fā)的優(yōu)化建議。

三. 界面過度繪制(OverDraw)

3.1 過度繪制概念

    過度繪制是一個(gè)術(shù)語(yǔ)岛马,表示某些組件在屏幕上的一個(gè)像素點(diǎn)的繪制次數(shù)超過 1 次棉姐。

    通俗來(lái)講屠列,繪制界面可以類比成一個(gè)涂鴉客涂鴉墻壁,涂鴉是一件工作量很大的事情伞矩,墻面的每個(gè)點(diǎn)在涂鴉過程中可能被涂了各種各樣的顏色笛洛,但最終呈現(xiàn)的顏色卻只可能是 1 種。這意味著我們花大力氣涂鴉過程中那些非最終呈現(xiàn)的顏色對(duì)路人是不可見的乃坤,是一種對(duì)時(shí)間苛让、精力和資源的浪費(fèi),存在很大的改善空間湿诊。繪制界面同理狱杰,花了太多的時(shí)間去繪制那些堆疊在下面的、用戶看不到的東西厅须,這樣是在浪費(fèi)CPU周期和渲染時(shí)間仿畸!

    官方例子,被用戶激活的卡片在最上面,而那些沒有激活的卡片在下面朗和,在繪制用戶看不到的對(duì)象上花費(fèi)了太多的時(shí)間错沽。

3.2 追蹤過度繪制

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里打開 “ 調(diào)試 GPU 過度繪制 ” ,來(lái)查看應(yīng)用所有界面及分支界面下的過度繪制情況眶拉,方便進(jìn)行優(yōu)化千埃。

    Android 會(huì)在屏幕上顯示不同深淺的顏色來(lái)表示過度繪制:

沒顏色:沒有過度繪制,即一個(gè)像素點(diǎn)繪制了 1 次镀层,顯示應(yīng)用本來(lái)的顏色镰禾;

藍(lán)色:1倍過度繪制,即一個(gè)像素點(diǎn)繪制了 2 次唱逢;

綠色:2倍過度繪制吴侦,即一個(gè)像素點(diǎn)繪制了 3 次;

淺紅色:3倍過度繪制坞古,即一個(gè)像素點(diǎn)繪制了 4 次备韧;

深紅色:4倍過度繪制及以上,即一個(gè)像素點(diǎn)繪制了 5 次及以上痪枫;

    設(shè)備的硬件性能是有限的织堂,當(dāng)過度繪制導(dǎo)致應(yīng)用需要消耗更多資源(超過了可用資源)的時(shí)候性能就會(huì)降低,表現(xiàn)為卡頓奶陈、不流暢易阳、ANR 等。為了最大限度地提高應(yīng)用的性能和體驗(yàn)吃粒,就需要盡可能地減少過度繪制潦俺,即更多的藍(lán)色色塊而不是紅色色塊。

實(shí)際測(cè)試,常用以下兩點(diǎn)來(lái)作為過度繪制的測(cè)試指標(biāo)事示,將過度繪制控制在一個(gè)約定好的合理范圍內(nèi):

應(yīng)用所有界面以及分支界面均不存在超過4X過度繪制(深紅色區(qū)域)早像;

應(yīng)用所有界面以及分支界面下,3X過度繪制總面積(淺紅色區(qū)域)不超過屏幕可視區(qū)域的1/4肖爵;

3.3 過度繪制的根源

    過度繪制很大程度上來(lái)自于視圖相互重疊的問題卢鹦,其次還有不必要的背景重疊。

    官方例子劝堪,比如一個(gè)應(yīng)用所有的View都有背景的話冀自,就會(huì)看起來(lái)像第一張圖中那樣,而在去除這些不必要的背景之后(指的是Window的默認(rèn)背景幅聘、Layout的背景凡纳、文字以及圖片的可能存在的背景),效果就像第二張圖那樣帝蒿,基本沒有過度繪制的情況荐糜。

3.4 不合理的xml布局對(duì)繪制的影響

    當(dāng)布局文件的節(jié)點(diǎn)樹的深度越深,XML 中的標(biāo)簽和屬性設(shè)置越多葛超,對(duì)界面的顯示有災(zāi)難性影響暴氏。

    一個(gè)界面要顯示出來(lái),第一步會(huì)進(jìn)行解析布局绣张,在 requestLayout 之后還要進(jìn)行一系列的 measure 答渔、 layout 、 draw 操作侥涵,若布局文件嵌套過深沼撕、擁有的標(biāo)簽屬性過于臃腫,每一步的執(zhí)行時(shí)間都會(huì)受到影響芜飘,而界面的顯示是進(jìn)行完這些操作后才會(huì)顯示的务豺,所以每一步操作的時(shí)間增長(zhǎng),最終顯示的時(shí)間就會(huì)越長(zhǎng)嗦明。

四. 渲染性能(Rendering)

4.1 渲染性能概念

    渲染性能往往是掉幀的罪魁禍?zhǔn)琢ぃ@種問題很常見,讓人頭疼娶牌。好在 Android 給我們提供了一個(gè)強(qiáng)大的工具奔浅,幫助我們非常容易追蹤性能渲染問題,看到究竟是什么導(dǎo)致你的應(yīng)用出現(xiàn)卡頓诗良、掉幀汹桦。

4.2 追蹤渲染性能

    通過在 Android 設(shè)備的設(shè)置 APP 的開發(fā)者選項(xiàng)里打開 “ GPU 呈現(xiàn)模式分析 ” 選項(xiàng),選擇 ” 在屏幕上顯示為條形圖 “ 鉴裹。
image
    這個(gè)工具會(huì)在Android 設(shè)備的屏幕上實(shí)時(shí)顯示當(dāng)前界面的最近 128 幀 的 GPU 繪制圖形數(shù)據(jù)营勤,包括 StatusBar 灵嫌、 NavBar 、 當(dāng)前界面的 GPU 繪制圖形柱狀圖數(shù)據(jù)葛作。我們一般只需關(guān)心當(dāng)前界面的 GPU 繪制圖形數(shù)據(jù)即可。
image
    界面上一共有 128 個(gè)小柱狀圖猖凛,代表的是當(dāng)前界面最近的 128 幀 GPU 繪制圖形數(shù)據(jù)赂蠢。一個(gè)小柱狀圖代表的這一幀畫面渲染的耗時(shí),柱狀圖越高代表耗時(shí)越長(zhǎng)辨泳。隨著界面的刷新虱岂,柱狀圖信息也會(huì)實(shí)時(shí)滾動(dòng)刷新。

    中間有一條綠線菠红,代表 16 ms 第岖,保持動(dòng)畫流暢的關(guān)鍵就在于讓這些垂直的柱狀條盡可能地保持在綠線下面,任何時(shí)候超過綠線,你就有可能丟失一幀的內(nèi)容。
image
    每一個(gè)柱狀圖都是由三種顏色構(gòu)成:藍(lán)试溯、紅蔑滓、黃。

藍(lán)色代表的是這一幀繪制 Display List 的時(shí)間遇绞。通俗來(lái)說键袱,就是記錄了需要花費(fèi)多長(zhǎng)時(shí)間在屏幕上更新視圖。用代碼語(yǔ)言來(lái)說摹闽,就是執(zhí)行視圖的 onDraw 方法蹄咖,創(chuàng)建或更新每一個(gè)視圖的 Display List 的時(shí)間。

紅色代表的是這一幀 OpenGL 渲染 Display List 所需要的時(shí)間付鹿。通俗來(lái)說澜汤,就是記錄了執(zhí)行視圖繪制的耗時(shí)。用代碼語(yǔ)言來(lái)說舵匾,就是 Android 用 OpenGL ES 的 API 接口進(jìn)行 2D 渲染 Display List 的時(shí)間俊抵。

黃色代表的是這一幀 CPU 等待 GPU 處理的時(shí)間。通俗來(lái)說纽匙,就是 CPU 等待 GPU 發(fā)出接到命令的回復(fù)的等待時(shí)間务蝠。用代碼語(yǔ)言來(lái)說,就是這是一個(gè)阻塞調(diào)用烛缔。

image
    實(shí)際測(cè)試馏段,常用以下兩點(diǎn)來(lái)作為渲染性能的測(cè)試指標(biāo),將渲染性能控制在一個(gè)約定好的合理范圍內(nèi):

執(zhí)行應(yīng)用的所有功能及分支功能践瓷,操作過程中涉及的柱狀條區(qū)域應(yīng)至少 90 % 保持到綠線下面院喜;

從用戶體檢的角度主觀判斷應(yīng)用在 512 M 內(nèi)存的 Android 設(shè)備下所有操作過程中的卡頓感是否能接受,不會(huì)感覺突兀怪異晕翠;

4.3 渲染性能差的根源

    當(dāng)你看到藍(lán)色的線較高的時(shí)候喷舀,可能是由于你的視圖突然無(wú)效了需要重新繪制砍濒,或者是自定義的視圖過于復(fù)雜耗時(shí)過長(zhǎng)。
image
    當(dāng)你看到紅色的線較高的時(shí)候硫麻,可能是由于你的視圖重新提交了需要重新繪制導(dǎo)致的(比如屏幕從豎屏旋轉(zhuǎn)成橫屏后當(dāng)前界面重新創(chuàng)建)爸邢,或者是自定義的視圖很復(fù)雜,繪制起來(lái)很麻煩拿愧,導(dǎo)致耗時(shí)過長(zhǎng)杠河。比如下面這種視圖:
image
    當(dāng)你看到黃色的線較高的時(shí)候,那就意味著你給 GPU 太多的工作浇辜,太多的負(fù)責(zé)視圖需要 OpenGL 命令去繪制和處理券敌,導(dǎo)致 CPU 遲遲沒等到 GPU 發(fā)出接到命令的回復(fù)。

4.4 檢測(cè)說明

    這個(gè)工具能夠很好地幫助你找到渲染相關(guān)的問題柳洋,幫助你找到卡頓的性能瓶頸待诅,追蹤究竟是什么導(dǎo)致被測(cè)應(yīng)用出現(xiàn)卡頓、變慢的情況熊镣,以便在代碼層面進(jìn)行優(yōu)化卑雁。甚至讓負(fù)責(zé)產(chǎn)品設(shè)計(jì)的人去改善他的設(shè)計(jì),以獲得良好的用戶體驗(yàn)轧钓。

    檢測(cè)渲染性能時(shí)序厉,常伴隨著開啟“ 嚴(yán)格模式 ” 查看應(yīng)用哪些情景在 UI 線程(主線程)上執(zhí)行時(shí)間過長(zhǎng)。

    另外有些強(qiáng)大但可能少用的工具在測(cè)試性能渲染時(shí)輔助分析毕箍,比如:

HierarchyViewer:這個(gè)工具常用來(lái)查看界面的視圖結(jié)構(gòu)是否過于復(fù)雜弛房,用于了解哪些視圖過度繪制,又該如何進(jìn)行改進(jìn)而柑;

Tracer for OpenGL:這個(gè)工具收集了所有UI界面發(fā)給GPU的繪制命令文捶。常用于輔助開發(fā)人員 DEBUG 、定位一些 HierarchyViewer 工具定位不了的疑難渲染細(xì)節(jié)問題媒咳。

4.5 UI繪制機(jī)制的補(bǔ)充說明

    如上面所說粹排,布局和 UI 組件等都會(huì)先經(jīng)過 CPU 計(jì)算成 GPU 能夠識(shí)別并繪制的多邊形( Polygons ),紋理( Texture )涩澡,然后交給 GPU 進(jìn)行柵格化渲染顽耳,再將處理結(jié)果傳到屏幕上顯示。 “ CPU 計(jì)算成 GPU 能夠識(shí)別并繪制的對(duì)象 ” 這個(gè)操作是在 DisplayList 的幫助下完成的妙同。DisplayList 擁有要交給 GPU 柵格化渲染到屏幕上的數(shù)據(jù)信息射富。
image
    DisplayList 會(huì)在某個(gè)視圖第一次需要渲染時(shí)創(chuàng)建。當(dāng)該視圖有類似位置被移動(dòng)等變化而需要重新渲染這個(gè)視圖的時(shí)候粥帚,則只需 GPU 額外執(zhí)行一次渲染指令冰更新到屏幕上就夠了胰耗。但如果視圖中的繪制內(nèi)容發(fā)生變化時(shí)(比如不可見了),那之間的 DisplayList 就無(wú)法繼續(xù)使用了芒涡,這時(shí)系統(tǒng)就會(huì)重新執(zhí)行一次重新創(chuàng)建 DisplayList 柴灯、渲染DisplayList 并更新到屏幕上卖漫。這個(gè)流程的表現(xiàn)性能取決于該視圖的復(fù)雜程度。

五. 布局邊界合理性

    這一章節(jié)比較簡(jiǎn)單赠群,考慮到應(yīng)該沒受眾羊始,故不展開討論。

六. 給開發(fā)的界面優(yōu)化 Advice

6.1 優(yōu)化布局的結(jié)構(gòu)

    布局結(jié)構(gòu)太復(fù)雜乎串,會(huì)減慢渲染的速度店枣,造成性能瓶頸。我們可以通過以下這些慣用叹誉、有效的布局原則來(lái)優(yōu)化:

避免復(fù)雜的View層級(jí)。布局越復(fù)雜就越臃腫闷旧,就越容易出現(xiàn)性能問題长豁,尋找最節(jié)省資源的方式去展示嵌套的內(nèi)容;

盡量避免在視圖層級(jí)的頂層使用相對(duì)布局 RelativeLayout 忙灼。相對(duì)布局 RelativeLayout 比較耗資源匠襟,因?yàn)橐粋€(gè)相對(duì)布局 RelativeLayout 需要兩次度量來(lái)確保自己處理了所有的布局關(guān)系,而且這個(gè)問題會(huì)伴隨著視圖層級(jí)中的相對(duì)布局 RelativeLayout 的增多该园,而變得更嚴(yán)重酸舍;

布局層級(jí)一樣的情況建議使用線性布局 LinearLayout 代替相對(duì)布局 RelativeLayout,因?yàn)榫€性布局 LinearLayout 性能要更高一些里初;確實(shí)需要對(duì)分支進(jìn)行相對(duì)布局 RelativeLayout 的時(shí)候啃勉,可以考慮更優(yōu)化的網(wǎng)格布局 GridLayout ,它已經(jīng)預(yù)處理了分支視圖的關(guān)系双妨,可以避免兩次度量的問題淮阐;

相對(duì)復(fù)雜的布局建議采用相對(duì)布局 RelativeLayout ,相對(duì)布局 RelativeLayout 可以簡(jiǎn)單實(shí)現(xiàn)線性布局 LinearLayout 嵌套才能實(shí)現(xiàn)的布局刁品;

不要使用絕對(duì)布局 AbsoluteLayout 泣特;

將可重復(fù)使用的組件抽取出來(lái)并用 標(biāo)簽進(jìn)行重用。如果應(yīng)用多個(gè)地方的 UI 用到某個(gè)布局挑随,就將其寫成一個(gè)布局部件状您,便于各個(gè) UI 重用。官方詳解 「 戳我 」

使用 merge 標(biāo)簽減少布局的嵌套層次兜挨,官方詳解 「 戳我 」膏孟;

去掉多余的不可見背景。有多層背景顏色的布局暑劝,只留最上層的對(duì)用戶可見的顏色即可骆莹,其他用戶不可見的底層顏色可以去掉,減少無(wú)效的繪制操作担猛;

盡量避免使用 layoutweight 屬性幕垦。使用包含 layoutweight 屬性的線性布局 LinearLayout 每一個(gè)子組件都需要被測(cè)量?jī)纱味猓瑫?huì)消耗過多的系統(tǒng)資源。在使用 ListView 標(biāo)簽與 GridView 標(biāo)簽的時(shí)候先改,這個(gè)問題顯的尤其重要疚察,因?yàn)樽咏M件會(huì)重復(fù)被創(chuàng)建。平分布局可以使用相對(duì)布局 RelativeLayout 里一個(gè) 0dp 的 view 做分割線來(lái)搞定仇奶,如果不行貌嫡,那就……;

合理的界面的布局結(jié)構(gòu)應(yīng)是寬而淺该溯,而不是窄而深岛抄;

6.2 優(yōu)化處理邏輯

按需載入視圖。某些不怎么重用的耗資源視圖狈茉,可以等到需要的時(shí)候再加載夫椭,提高UI渲染速度;

使用 ViewStub 標(biāo)簽來(lái)加載一些不常用的布局氯庆;

動(dòng)態(tài)地 inflation view 性能要比用 ViewStub 標(biāo)簽的 setVisiblity 性能要好蹭秋,當(dāng)然某些功能的實(shí)現(xiàn)采用 ViewStub 標(biāo)簽更合適;

盡量避免不必要的耗資源操作堤撵,節(jié)省寶貴的運(yùn)算時(shí)間仁讨;

避免在 UI 線程進(jìn)行繁重的操作。耗資源的操作(比如 IO 操作实昨、網(wǎng)絡(luò)操作洞豁、SQL 操作、列表刷新等)耗資源的操作應(yīng)用后臺(tái)進(jìn)程去實(shí)現(xiàn)屠橄,不能占用 UI 線程族跛,UI 線程是主線程,主線程是保持程序流暢的關(guān)鍵锐墙,應(yīng)該只操作那些核心的 UI 操作礁哄,比如處理視圖的屬性和繪制;

最小化喚醒機(jī)制溪北。我們常用廣播來(lái)接收那些期望響應(yīng)的消息和事件桐绒,但過多的響應(yīng)超過本身需求的話,會(huì)消耗多余的 Android 設(shè)備性能和資源之拨。所以應(yīng)該最小化喚醒機(jī)制茉继,當(dāng)應(yīng)用不關(guān)心這些消失和事件時(shí),就關(guān)閉廣播蚀乔,并慎重選擇那些要響應(yīng)的 Intent 烁竭。

為低端設(shè)備考慮,比如 512M 內(nèi)存吉挣、雙核 CPU 派撕、低分辨率婉弹,確保你的應(yīng)用可以滿足不同水平的設(shè)備。

優(yōu)化應(yīng)用的啟動(dòng)速度终吼。當(dāng)應(yīng)用啟動(dòng)一個(gè)應(yīng)用時(shí)镀赌,界面的盡快反饋顯示可以給用戶一個(gè)良好的體驗(yàn)。為了啟動(dòng)更快际跪,可以延遲加載一些 UI 以及避免在應(yīng)用 Application 層級(jí)初始化代碼商佛。

我自己是一名從事了5年Android的老程序員,辭職目前在做講師姆打,今年年初我花了一個(gè)月整理了一份最適合2019年學(xué)習(xí)的Android學(xué)習(xí)干貨良姆,各個(gè)方面都有整理,送給每一位Android開發(fā)的小伙伴幔戏,這里是開發(fā)者聚集地歇盼,歡迎初學(xué)和進(jìn)階中的小伙伴。
加QQ群:457848807獲取學(xué)習(xí)資料 以及文章源碼
image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末评抚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伯复,更是在濱河造成了極大的恐慌慨代,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啸如,死亡現(xiàn)場(chǎng)離奇詭異侍匙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)叮雳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門想暗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人帘不,你說我怎么就攤上這事说莫。” “怎么了寞焙?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵储狭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我捣郊,道長(zhǎng)辽狈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任呛牲,我火速辦了婚禮刮萌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娘扩。我一直安慰自己着茸,他們只是感情好壮锻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著元扔,像睡著了一般躯保。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上澎语,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天途事,我揣著相機(jī)與錄音,去河邊找鬼擅羞。 笑死尸变,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的减俏。 我是一名探鬼主播召烂,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼娃承!你這毒婦竟也來(lái)了奏夫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤历筝,失蹤者是張志新(化名)和其女友劉穎酗昼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梳猪,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡麻削,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了春弥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呛哟。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖匿沛,靈堂內(nèi)的尸體忽然破棺而出扫责,到底是詐尸還是另有隱情,我是刑警寧澤俺祠,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布公给,位于F島的核電站,受9級(jí)特大地震影響蜘渣,放射性物質(zhì)發(fā)生泄漏淌铐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一蔫缸、第九天 我趴在偏房一處隱蔽的房頂上張望腿准。 院中可真熱鬧,春花似錦、人聲如沸吐葱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弟跑。三九已至灾前,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間孟辑,已是汗流浹背哎甲。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饲嗽,地道東北人炭玫。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像貌虾,于是被迫代替她去往敵國(guó)和親吞加。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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