性能優(yōu)化——布局優(yōu)化

我們通過對View的源碼分析验游,其實發(fā)現(xiàn)View的測量和繪制都是遞歸實現(xiàn)的苫幢,布局是一個多叉樹的結(jié)構(gòu)职员,多叉樹遍歷所需的時間跟樹的結(jié)構(gòu)是相關(guān)的,布局復(fù)雜那么遍歷View完成測量和繪制的時間就越久赊琳,過于復(fù)雜的布局也會影響到應(yīng)用的性能街夭。

1,Hierarchy Viewer的使用

Hierarchy Viewer是Android SDK提供的躏筏,用來檢測布局的嵌套和繪制時間的工具板丽,通過Hierarchy Viewer可以直觀的檢測布局的設(shè)計和屬性,從而找到布局中可優(yōu)化點趁尼。

下面是一個簡單的布局檐什,用它來說明Hierarchy Viewer的使用方式:

圖1、示例程序運行效果

布局如下:
activity_main:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="10dp"
        android:hint="Edit something here" />

    <include layout="@layout/ok_cancel_layout"/>

</LinearLayout>

ok_cancel_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <Button
        android:id="@+id/ok"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:text="OK" />

    <Button
        android:id="@+id/cancel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="10dp"
        android:text="Cancel" />

</LinearLayout>
1弱卡,開啟Hierarchy Viewer

AndroidStudio中開啟Hierarchy Viewer步驟是:選擇Tools->Android->Android Device Monitor乃正,在Android Device Monitor中有可能Hierarchy Viewer被隱藏了,按照下圖的步驟就可以打開


圖2婶博、Android Device Monitor開啟Hierarchy Viewer

打開后:

圖3瓮具、Hierarchy Viewer的主界面

Windows:顯示當前設(shè)備信息,以及當前設(shè)備的所有頁面列表。
View Properties:當前選中View的屬性名党。
TreeView:把Activity中所有控件(View)的層次結(jié)構(gòu)從左到右顯示出來叹阔,其中最右邊部分是最底層的控件(View)。
Tree Overview:全局概覽传睹,以縮略圖的方式顯示整個應(yīng)用中各控件的層次關(guān)系耳幢,并且框出TreeView窗口中顯示部分在全局中的位置,如果一個界面中的控件和層級比較多欧啤,可以通過鼠標移動這個顯示區(qū)域移動睛藻。
Layout View:整體Layout布局圖,以手機屏幕上真實位置呈現(xiàn)出來邢隧,在TreeView中選中某一個控件時店印,會在Layout View用紅色的框標注。

2倒慧,使用Hierarchy Viewer查看布局層級與耗時

(1)查看布局層級:在Window窗口點擊選擇需要查看的Activity按摘,然后點擊Load View Hierarchy按鈕即可打開,顯示在TreeView的窗口中纫谅,從左到右可以移動鼠標進行查看炫贤。
(2)查看耗時:在菜單欄中單擊Obtain layout times for tree rooted at selected node按鈕


圖4,計算某個View的耗時

這時付秕,就可以在TreeView中的View多了一些信息兰珍,截圖如下:

圖5、計算耗時的結(jié)果顯示

圖中灰色方框中信息從上到下分別的意思是盹牧,1 view表示這個節(jié)點下只有1個View了,就是自己本身的View励幼,如果某個節(jié)點顯示3 views汰寓,那么就表示該節(jié)點下面包括自己,一共有3個元素(自身+2個子view)苹粟。下面的時間表示Measure有滑、Layout以及Draw三個階段的耗時。
最后一個框有不同色的三個指示燈嵌削,分別對應(yīng)當前控件在測量毛好、布局以及畫視圖三個階段,顏色表示這個控件占用的時間百分比苛秕,如果是綠色的肌访,表示該控件在該階段比其他50%的控件的速度要快,黃色表示比其他50%的控件的速度要慢艇劫,紅色表示該控件在該階段的處理速度是最慢的吼驶,就需要注意了。


2,Lint

Android Lint是代碼檢查工具蟹演,通過代碼靜態(tài)檢查风钻,可以發(fā)現(xiàn)潛在的代碼問題,并給出優(yōu)化建議酒请。Lint的功能非常強大骡技,可以掃描出我們項目中的代碼的正確性、安全性羞反、性能問題布朦、可用、可達苟弛,甚至是國際化問題喝滞,并且針對不同的問題給出不同的錯誤級別:
Fatal > Error > Warning > Information > Ignore,我們可以根據(jù)這些錯誤級別來改造代碼膏秫,使得代碼更加健壯右遭。
同時Lint還可以用來檢查布局,使用Lint掃描前缤削,先配置需要檢查的項目窘哈,只需要檢查Layout層級深度。File——Settings——Inspections——Android Lint

圖6亭敢、Android Lint配置.png

如圖所示滚婉,在Android Lint的Performance中找到Layout has too many views 和 Layout hierarchy is too deep,勾上帅刀,其余的都取消让腹,只要保證Lint就只會拋出與這2個屬性相關(guān)的信息了。其中:
Layout has too many views表示控件太多扣溺,默認超過80個控件會提示該問題骇窍。
Layout hierarchy is too deep表示布局太深,默認層級超過10層會提示該問題锥余,可以自定義環(huán)境變量ANDROID_LINT_MAX_DEPTH來修改腹纳。布局深度增加會導(dǎo)致內(nèi)存消耗也隨之增加,因此布局盡可能淺而寬驱犹。

配置好后嘲恍,點擊確定。然后返回AndroidStudio中雄驹,在菜單欄中選擇Analyze——Inspect Code佃牛,然后選擇整個工程或者某個Moudle

圖7、分析布局

為了方便測試医舆,我將上面用到的xml布局中稍作修改吁脱,一共嵌套了11層桑涎,看看就知道有多恐怖了。

圖8兼贡、測試用例嵌套11層

然后我們用Lint工具分析一下代碼攻冷,立馬就出了提示:

圖9、Lint提示xml中嵌套過多

Lint里提示到activity_index的布局嵌套超過了10層遍希,提示到如此明顯的地步等曼,那我們就能根據(jù)提示的消息來修改或者優(yōu)化這部分的布局了。


3凿蒜,布局的優(yōu)化方式

關(guān)于布局的優(yōu)化方式網(wǎng)上有很多的介紹禁谦,這里推薦看看郭大神的博客,寫的簡潔明了
Android最佳性能實踐(四)——布局優(yōu)化技巧
總結(jié):
提高布局效率的方法總體來說就是減少層級废封,提高繪制速度和布局復(fù)用州泊。影響布局效率主要有以下幾點:
**
(1)布局的層級越少,加載速度越快漂洋。因為View的結(jié)構(gòu)是典型的多叉樹的結(jié)構(gòu)遥皂,減少布局層級,明顯減少了多叉樹的深度刽漂,這樣在遍歷遞歸測量和繪制的時間就相應(yīng)較少很多演训。
(2)減少同一層級控件的數(shù)量,加載速度會變快贝咙。
(3)一個控件的屬性越少样悟,解析越快。刪除控件中的無用屬性也是加快解析速度的一種必要手段庭猩。
(4)盡量多使用RelativeLayout或LinearLayout窟她,不要使用絕對布局AbsoluteLayout。同時蔼水,在大部分情況下推薦使用RelativeLayout而不是LinearLayout震糖,因為前者在相同情況下,嵌套的層次會少徙缴。
(5)將可復(fù)用的組件抽取出來并通過<include/>標簽使用试伙。
(6)使用<ViewStub/>標簽加載一些不常用的布局嘁信。<ViewStub/>修飾的布局不會立刻就加載于样,而是調(diào)用了inflate方法或者View.VISIBILITY屬性后才加載到內(nèi)存。這種方式特別適合用在無網(wǎng)絡(luò)環(huán)境給頁面做提示的功能上潘靖。
(7)使用<merge/>標簽減少布局的嵌套層次穿剖。
(8)盡可能少用wrap_content,wrap_content會增加布局measure時的計算成本卦溢,已知寬高為固定值時糊余,不用wrap_content秀又。
**


4,避免過度繪制

可以參考Android性能優(yōu)化之如何避免Overdraw
Overdraw就是過度繪制贬芥,是指在一幀的時間內(nèi)(16.67ms)像素被繪制了多次吐辙,理論上一個像素每次只繪制一次是最優(yōu)的,但是由于重疊的布局導(dǎo)致一些像素會被多次繪制蘸劈,而每次繪制都會對應(yīng)到CPU的一組繪圖命令和GPU的一些操作昏苏,當這個操作耗時超過16.67ms時,就會出現(xiàn)掉幀現(xiàn)象威沫,也就是我們所說的卡頓贤惯,所以對重疊不可見元素的重復(fù)繪制會產(chǎn)生額外的開銷,需要盡量減少Overdraw的發(fā)生棒掠。
Android提供了測量Overdraw的選項孵构,在開發(fā)者選項-調(diào)試GPU過度繪制(Show GPU Overdraw),打開選項就可以看到當前頁面Overdraw的狀態(tài)烟很,就可以觀察屏幕的繪制狀態(tài)颈墅。該工具會使用三種不同的顏色繪制屏幕,來指示overdraw發(fā)生在哪里以及程度如何溯职,其中:
沒有顏色: 意味著沒有overdraw精盅。像素只畫了一次。
藍色: 意味著overdraw 1倍谜酒。像素繪制了兩次叹俏。大片的藍色還是可以接受的(若整個窗口是藍色的,可以擺脫一層)僻族。
綠色: 意味著overdraw 2倍粘驰。像素繪制了三次。中等大小的綠色區(qū)域是可以接受的但你應(yīng)該嘗試優(yōu)化述么、減少它們蝌数。
淺紅: 意味著overdraw 3倍。像素繪制了四次度秘,小范圍可以接受顶伞。
暗紅: 意味著overdraw 4倍。像素繪制了五次或者更多剑梳。這是錯誤的唆貌,要修復(fù)它們。

圖10、OverDraw

如何避免過度繪制?
除了上述8點布局優(yōu)化建議外裂逐,還有
(1)布局上的優(yōu)化
在XML布局上,如果出現(xiàn)了過度繪制的情況酪刀,可以使用Hierarchy View來查看具體的層級情況粹舵,可以通過XML布局優(yōu)化來減少層級。需要注意的是骂倘,在使用XML文件布局時眼滤,會設(shè)置很多背景,如果不是必需的历涝,盡量移除柠偶。布局優(yōu)化總結(jié)為以下幾點:
移除XML中非必需的背景,或根據(jù)條件設(shè)置睬关。
移除Window默認的背景诱担。
按需顯示占位背景圖片。
使用Android自帶的一些主題時电爹,activity往往會被設(shè)置一個默認的背景蔫仙,這個背景由DecorView持有。當自定義布局有一個全屏的背景時丐箩,比如設(shè)置了這個界面的全屏黑色背景摇邦,DecorView的背景此時對我們來說是無用的,但是它會產(chǎn)生一次Overdraw屎勘。因此沒有必要的話施籍,也可以移除,代碼如下:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.getWindow().setBackgroundDrawable(null);
        setContentView(R.layout.activity_index);
    }

針對ListView中的Avatar ImageView的設(shè)置概漱,在getView的代碼中丑慎,判斷是否獲取對應(yīng)的Bitmap,獲取Avatar的圖像之后瓤摧,把ImageView的Background設(shè)置為Transparent竿裂,只有當圖像沒有獲取到時,才設(shè)置對應(yīng)的Background占位圖片照弥,這樣可以避免因為給Avatar設(shè)置背景圖而導(dǎo)致的過度渲染腻异。

(2)自定義View優(yōu)化
雖然自定義View減少了Layout的層級,但在實際繪制時也是會過度繪制的这揣。原因是有些過于復(fù)雜的自定義View(通常重寫了onDraw方法)悔常,Android系統(tǒng)無法檢測在onDraw中具體會執(zhí)行什么操作,無法監(jiān)控并自動優(yōu)化给赞,也就無法避免Overdraw了机打。但是在自定義View中可以通過canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域。這個方法可以指定一塊矩形區(qū)域塞俱,只有在這個區(qū)域內(nèi)才會被繪制姐帚,其他的區(qū)域會被忽視吏垮。canvas.clipRect()可以很好地幫助那些有多組重疊組件的自定義View來控制顯示的區(qū)域障涯。clipRect方法還可以幫助節(jié)約CPU與GPU資源罐旗,在clipRect區(qū)域之外的繪制指令都不會被執(zhí)行,那些部分內(nèi)容在矩形區(qū)域內(nèi)的組件唯蝶,仍然會得到繪制九秀,并且可以使用canvas.quickreject()來判斷是否沒和某個矩形相交,從而跳過那些非矩形區(qū)域內(nèi)的繪制操作粘我。


參考資料:
Android最佳性能實踐(四)——布局優(yōu)化技巧
Android性能優(yōu)化之如何避免Overdraw

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鼓蜒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子征字,更是在濱河造成了極大的恐慌都弹,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匙姜,死亡現(xiàn)場離奇詭異畅厢,居然都是意外死亡,警方通過查閱死者的電腦和手機氮昧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門框杜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袖肥,你說我怎么就攤上這事咪辱。” “怎么了椎组?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵油狂,是天一觀的道長。 經(jīng)常有香客問我寸癌,道長选调,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任灵份,我火速辦了婚禮仁堪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘填渠。我一直安慰自己弦聂,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布氛什。 她就那樣靜靜地躺著莺葫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枪眉。 梳的紋絲不亂的頭發(fā)上捺檬,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音贸铜,去河邊找鬼堡纬。 笑死聂受,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的烤镐。 我是一名探鬼主播蛋济,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼炮叶!你這毒婦竟也來了碗旅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤镜悉,失蹤者是張志新(化名)和其女友劉穎祟辟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侣肄,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡川尖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了茫孔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叮喳。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缰贝,靈堂內(nèi)的尸體忽然破棺而出馍悟,到底是詐尸還是另有隱情,我是刑警寧澤剩晴,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布锣咒,位于F島的核電站,受9級特大地震影響赞弥,放射性物質(zhì)發(fā)生泄漏毅整。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一绽左、第九天 我趴在偏房一處隱蔽的房頂上張望悼嫉。 院中可真熱鬧,春花似錦拼窥、人聲如沸戏蔑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽总棵。三九已至,卻和暖如春改含,著一層夾襖步出監(jiān)牢的瞬間情龄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骤视,地道東北人鞍爱。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像尚胞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子帜慢,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

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