《Android性能優(yōu)化》學(xué)習(xí)筆記1——渲染篇

Google近期在Udacity上發(fā)布了 Android性能優(yōu)化的在線課程原在,分別從渲染矛缨,運算與內(nèi)存顶掉,電量幾個方面介紹了如何去優(yōu)化性能迷守,這些課程是Google之前在Youtube上發(fā)布的 Android性能優(yōu)化典范專題課程的細化與補充却汉。

下面是本文作者 @胡凱me 對渲染恶阴、運算先煎、內(nèi)存屯碴、電量篇章的學(xué)習(xí)筆記践叠,部分內(nèi)容和前面的性能優(yōu)化典范有重合言缤,歡迎大家一起學(xué)習(xí)交流!

渲染篇

  1. Why Rendering Performance Matters

現(xiàn)在有不少App為了達到很華麗的視覺效果禁灼,會需要在界面上層疊很多的視圖組件管挟,但是這會很容易引起性能問題。如何平衡Design與Performance就很需要智慧了弄捕。

2) Defining ‘Jank’
大多數(shù)手機的屏幕刷新頻率是60hz僻孝,如果在1000/60=16.67ms內(nèi)沒有辦法把這一幀的任務(wù)執(zhí)行完畢导帝,就會發(fā)生丟幀的現(xiàn)象。丟幀越多穿铆,用戶感受到的卡頓情況就越嚴重您单。

3) Rendering Pipeline: Common Problems
渲染操作通常依賴于兩個核心組件:CPU與GPU。CPU負責(zé)包括Measure荞雏,Layout虐秦,Record,Execute的計算操作凤优,GPU負責(zé)Rasterization(柵格化)操作悦陋。CPU通常存在的問題的原因是存在非必需的視圖組件,它不僅僅會帶來重復(fù)的計算操作别洪,而且還會占用額外的GPU資源叨恨。

4) Android UI and the GPU
了解Android是如何利用GPU進行畫面渲染有助于我們更好的理解性能問題。一個很直接的問題是:activity的畫面是如何繪制到屏幕上的挖垛?那些復(fù)雜的XML布局文件又是如何能夠被識別并繪制出來的痒钝?


Resterization柵格化是繪制那些Button,Shape痢毒,Path送矩,String,Bitmap等組件最基礎(chǔ)的操作哪替。它把那些組件拆分到不同的像素上進行顯示栋荸。這是一個很費時的操作,GPU的引入就是為了加快柵格化的操作凭舶。
CPU負責(zé)把UI組件計算成Polygons晌块,Texture紋理,然后交給GPU進行柵格化渲染帅霜。

然而每次從CPU轉(zhuǎn)移到GPU是一件很麻煩的事情匆背,所幸的是OpenGL ES可以把那些需要渲染的紋理Hold在GPUMemory里面,在下次需要渲染的時候直接進行操作身冀。所以如果你更新了GPU所hold住的紋理內(nèi)容钝尸,那么之前保存的狀態(tài)就丟失了。
在Android里面那些由主題所提供的資源搂根,例如Bitmaps珍促,Drawables都是一起打包到統(tǒng)一的Texture紋理當(dāng)中,然后再傳遞到GPU里面剩愧,這意味著每次你需要使用這些資源的時候猪叙,都是直接從紋理里面進行獲取渲染的。當(dāng)然隨著UI組件的越來越豐富,有了更多演變的形態(tài)沐悦。例如顯示圖片的時候成洗,需要先經(jīng)過CPU的計算加載到內(nèi)存中,然后傳遞給GPU進行渲染藏否。文字的顯示比較復(fù)雜瓶殃,需要先經(jīng)過CPU換算成紋理,然后交給GPU進行渲染副签,返回到CPU繪制單個字符的時候遥椿,再重新引用經(jīng)過GPU渲染的內(nèi)容。動畫則存在一個更加復(fù)雜的操作流程淆储。
為了能夠使得App流暢冠场,我們需要在每幀16ms以內(nèi)處理完所有的CPU與GPU的計算,繪制本砰,渲染等等操作碴裙。

5) GPU Problem: Overdraw
Overdraw(過度繪制)描述的是屏幕上的某個像素在同一幀的時間內(nèi)被繪制了多次。在多層次重疊的UI結(jié)構(gòu)里面点额,如果不可見的UI也在做繪制的操作舔株,會導(dǎo)致某些像素區(qū)域被繪制了多次。這樣就會浪費大量的CPU以及GPU資源还棱。


當(dāng)設(shè)計上追求更華麗的視覺效果的時候载慈,我們就容易陷入采用復(fù)雜的多層次重疊視圖來實現(xiàn)這種視覺效果的怪圈。這很容易導(dǎo)致大量的性能問題珍手,為了獲得最佳的性能办铡,我們必須盡量減少Overdraw的情況發(fā)生。
幸運的是琳要,我們可以通過手機設(shè)置里面的開發(fā)者選項寡具,打開Show GPU Overdraw的選項,觀察UI上的Overdraw情況稚补。

藍色童叠、淡綠、淡紅孔厉、深紅代表了4種不同程度的Overdraw情況,我們的目標(biāo)就是盡量減少紅色Overdraw帖努,看到更多的藍色區(qū)域撰豺。

6) Visualize and Fix Overdraw - Quiz & Solution
這里舉了一個例子,通過XML文件可以看到有好幾處非必需的background拼余。通過把XML中非必需的background移除之后污桦,可以顯著減少布局的過度繪制。其中一個比較有意思的地方是:針對ListView中的Avatar ImageView的設(shè)置匙监,在getView的代碼里面凡橱,判斷是否獲取到對應(yīng)的Bitmap小作,在獲取到Avatar的圖像之后,把ImageView的Background設(shè)置為Transparent稼钩,只有當(dāng)圖像沒有獲取到的時候才設(shè)置對應(yīng)的Background占位圖片顾稀,這樣可以避免因為給Avatar設(shè)置背景圖而導(dǎo)致的過度渲染。


總結(jié)一下坝撑,優(yōu)化步驟如下:
移除Window默認的Background
移除XML布局文件中非必需的Background
按需顯示占位背景圖片

7) ClipRect & QuickReject
前面有提到過静秆,對不可見的UI組件進行繪制更新會導(dǎo)致Overdraw。例如Nav Drawer從前置可見的Activity滑出之后巡李,如果還繼續(xù)繪制那些在NavDrawer里面不可見的UI組件抚笔,這就導(dǎo)致了Overdraw。為了解決這個問題侨拦,Android系統(tǒng)會通過避免繪制那些完全不可見的組件來盡量減少Overdraw殊橙。那些Nav Drawer里面不可見的View就不會被執(zhí)行浪費資源。


但是不幸的是狱从,對于那些過于復(fù)雜的自定義的View(通常重寫了onDraw方法)膨蛮,Android系統(tǒng)無法檢測在onDraw里面具體會執(zhí)行什么操作,系統(tǒng)無法監(jiān)控并自動優(yōu)化矫夯,也就無法避免Overdraw了鸽疾。但是我們可以通過canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域。這個方法可以指定一塊矩形區(qū)域训貌,只有在這個區(qū)域內(nèi)才會被繪制制肮,其他的區(qū)域會被忽視。這個API可以很好的幫助那些有多組重疊組件的自定義View來控制顯示的區(qū)域递沪。同時clipRect方法還可以幫助節(jié)約CPU與GPU資源豺鼻,在clipRect區(qū)域之外的繪制指令都不會被執(zhí)行,那些部分內(nèi)容在矩形區(qū)域內(nèi)的組件款慨,仍然會得到繪制儒飒。

除了clipRect方法之外,我們還可以使用 canvas.quickreject()來判斷是否沒和某個矩形相交檩奠,從而跳過那些非矩形區(qū)域內(nèi)的繪制操作桩了。

8) Apply clipRect and quickReject - Quiz & Solution


上面的示例圖中顯示了一個自定義的View,主要效果是呈現(xiàn)多張重疊的卡片埠戳。這個View的onDraw方法如下圖所示:

打開開發(fā)者選項中的顯示過度渲染井誉,可以看到我們這個自定義的View部分區(qū)域存在著過度繪制。那么是什么原因?qū)е逻^度繪制的呢整胃?

9) Fixing Overdraw with Canvas API
下面的代碼顯示了如何通過clipRect來解決自定義View的過度繪制颗圣,提高自定義View的繪制性能:


下面是優(yōu)化過后的效果:

10) Layouts, Invalidations and Perf
Android需要把XML布局文件轉(zhuǎn)換成GPU能夠識別并繪制的對象。這個操作是在DisplayList的幫助下完成的。DisplayList持有所有將要交給GPU繪制到屏幕上的數(shù)據(jù)信息在岂。
在某個View第一次需要被渲染時奔则,Display List會因此被創(chuàng)建,當(dāng)這個View要顯示到屏幕上時蔽午,我們會執(zhí)行GPU的繪制指令來進行渲染易茬。
如果View的Property屬性發(fā)生了改變(例如移動位置),我們就僅僅需要Execute Display List就夠了祠丝。


然而如果你修改了View中的某些可見組件的內(nèi)容疾呻,那么之前的DisplayList就無法繼續(xù)使用了,我們需要重新創(chuàng)建一個DisplayList并重新執(zhí)行渲染指令更新到屏幕上写半。

請注意:任何時候View中的繪制內(nèi)容發(fā)生變化時岸蜗,都會需要重新創(chuàng)建DisplayList,渲染DisplayList叠蝇,更新到屏幕上等一系列操作璃岳。這個流程的表現(xiàn)性能取決于你的View的復(fù)雜程度,View的狀態(tài)變化以及渲染管道的執(zhí)行性能悔捶。舉個例子铃慷,假設(shè)某個Button的大小需要增大到目前的兩倍,在增大Button大小之前蜕该,需要通過父View重新計算并擺放其他子View的位置犁柜。修改View的大小會觸發(fā)整個HierarcyView的重新計算大小的操作。如果是修改View的位置則會觸發(fā)HierarchView重新計算其他View的位置堂淡。如果布局很復(fù)雜馋缅,這就會很容易導(dǎo)致嚴重的性能問題。

11) Hierarchy Viewer: Walkthrough
Hierarchy Viewer可以很直接的呈現(xiàn)布局的層次關(guān)系绢淀,視圖組件的各種屬性萤悴。我們可以通過紅,黃皆的,綠三種不同的顏色來區(qū)分布局的Measure覆履,Layout,Executive的相對性能表現(xiàn)如何费薄。

12) Nested Hierarchies and Performance
提升布局性能的關(guān)鍵點是盡量保持布局層級的扁平化硝全,避免出現(xiàn)重復(fù)的嵌套布局。例如下面的例子楞抡,有2行顯示相同內(nèi)容的視圖伟众,分別用兩種不同的寫法來實現(xiàn),他們有著不同的層級拌倍。



下圖顯示了使用2種不同的寫法赂鲤,在Hierarchy Viewer上呈現(xiàn)出來的性能測試差異:

13) Optimizing Your Layout
下圖舉例演示了如何優(yōu)化ListItem的布局,通過RelativeLayout替代舊方案中的嵌套LinearLayout來優(yōu)化布局柱恤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末数初,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子梗顺,更是在濱河造成了極大的恐慌泡孩,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寺谤,死亡現(xiàn)場離奇詭異仑鸥,居然都是意外死亡,警方通過查閱死者的電腦和手機变屁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門眼俊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粟关,你說我怎么就攤上這事疮胖。” “怎么了闷板?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵澎灸,是天一觀的道長。 經(jīng)常有香客問我遮晚,道長性昭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任县遣,我火速辦了婚禮糜颠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艺玲。我一直安慰自己括蝠,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布饭聚。 她就那樣靜靜地躺著忌警,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秒梳。 梳的紋絲不亂的頭發(fā)上法绵,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機與錄音酪碘,去河邊找鬼朋譬。 笑死,一個胖子當(dāng)著我的面吹牛兴垦,可吹牛的內(nèi)容都是我干的徙赢。 我是一名探鬼主播字柠,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼狡赐!你這毒婦竟也來了窑业?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤枕屉,失蹤者是張志新(化名)和其女友劉穎常柄,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搀擂,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡西潘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哨颂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喷市。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖威恼,靈堂內(nèi)的尸體忽然破棺而出东抹,到底是詐尸還是另有隱情,我是刑警寧澤沃测,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布缭黔,位于F島的核電站,受9級特大地震影響蒂破,放射性物質(zhì)發(fā)生泄漏馏谨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一附迷、第九天 我趴在偏房一處隱蔽的房頂上張望惧互。 院中可真熱鬧,春花似錦喇伯、人聲如沸喊儡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艾猜。三九已至,卻和暖如春捻悯,著一層夾襖步出監(jiān)牢的瞬間匆赃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工今缚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留算柳,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓姓言,卻偏偏與公主長得像瞬项,于是被迫代替她去往敵國和親蔗蹋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,876評論 2 361

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