新聞中心
Google近期在Udacity上發(fā)布了Android性能優(yōu)化的在線課程,分別從渲染,運(yùn)算與內(nèi)存,電量幾個(gè)方面介紹了如何去優(yōu)化性能,這些課程是Google之前在Youtube上發(fā)布的Android性能優(yōu)化典范專題課程的細(xì)化與補(bǔ)充。

我們提供的服務(wù)有:網(wǎng)站制作、成都網(wǎng)站制作、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、項(xiàng)城ssl等。為上千企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的項(xiàng)城網(wǎng)站制作公司
下面是渲染篇章的學(xué)習(xí)筆記,部分內(nèi)容和前面的性能優(yōu)化典范有重合,歡迎大家一起學(xué)習(xí)交流!
1)Why Rendering Performance Matters
現(xiàn)在有不少App為了達(dá)到很華麗的視覺效果,會(huì)需要在界面上層疊很多的視圖組件,但是這會(huì)很容易引起性能問題。如何平衡Design與Performance就很需要智慧了。
2)Defining ‘Jank’
大多數(shù)手機(jī)的屏幕刷新頻率是60hz,如果在1000/60=16.67ms內(nèi)沒有辦法把這一幀的任務(wù)執(zhí)行完畢,就會(huì)發(fā)生丟幀的現(xiàn)象。丟幀越多,用戶感受到的卡頓情況就越嚴(yán)重。
3)Rendering Pipeline: Common Problems
渲染操作通常依賴于兩個(gè)核心組件:CPU與GPU。CPU負(fù)責(zé)包括Measure,Layout,Record,Execute的計(jì)算操作,GPU負(fù)責(zé)Rasterization(柵格化)操作。CPU通常存在的問題的原因是存在非必需的視圖組件,它不僅僅會(huì)帶來重復(fù)的計(jì)算操作,而且還會(huì)占用額外的GPU資源。
4)Android UI and the GPU
了解Android是如何利用GPU進(jìn)行畫面渲染有助于我們更好的理解性能問題。一個(gè)很直接的問題是:activity的畫面是如何繪制到屏幕上的?那些復(fù)雜的XML布局文件又是如何能夠被識(shí)別并繪制出來的?
Resterization柵格化是繪制那些Button,Shape,Path,String,Bitmap等組件最基礎(chǔ)的操作。它把那些組件拆分到不同的像素上進(jìn)行顯示。這是一個(gè)很費(fèi)時(shí)的操作,GPU的引入就是為了加快柵格化的操作。
CPU負(fù)責(zé)把UI組件計(jì)算成Polygons,Texture紋理,然后交給GPU進(jìn)行柵格化渲染。
然而每次從CPU轉(zhuǎn)移到GPU是一件很麻煩的事情,所幸的是OpenGL ES可以把那些需要渲染的紋理Hold在GPU Memory里面,在下次需要渲染的時(shí)候直接進(jìn)行操作。所以如果你更新了GPU所hold住的紋理內(nèi)容,那么之前保存的狀態(tài)就丟失了。
在Android里面那些由主題所提供的資源,例如Bitmaps,Drawables都是一起打包到統(tǒng)一的Texture紋理當(dāng)中,然后再傳遞到GPU里面,這意味著每次你需要使用這些資源的時(shí)候,都是直接從紋理里面進(jìn)行獲取渲染的。當(dāng)然隨著UI組件的越來越豐富,有了更多演變的形態(tài)。例如顯示圖片的時(shí)候,需要先經(jīng)過CPU的計(jì)算加載到內(nèi)存中,然后傳遞給GPU進(jìn)行渲染。文字的顯示比較復(fù)雜,需要先經(jīng)過CPU換算成紋理,然后交給GPU進(jìn)行渲染,返回到CPU繪制單個(gè)字符的時(shí)候,再重新引用經(jīng)過GPU渲染的內(nèi)容。動(dòng)畫則存在一個(gè)更加復(fù)雜的操作流程。
為了能夠使得App流暢,我們需要在每幀16ms以內(nèi)處理完所有的CPU與GPU的計(jì)算,繪制,渲染等等操作。
5)GPU Problem: Overdraw
Overdraw(過度繪制)描述的是屏幕上的某個(gè)像素在同一幀的時(shí)間內(nèi)被繪制了多次。在多層次重疊的UI結(jié)構(gòu)里面,如果不可見的UI也在做繪制的操作,會(huì)導(dǎo)致某些像素區(qū)域被繪制了多次。這樣就會(huì)浪費(fèi)大量的CPU以及GPU資源。
當(dāng)設(shè)計(jì)上追求更華麗的視覺效果的時(shí)候,我們就容易陷入采用復(fù)雜的多層次重疊視圖來實(shí)現(xiàn)這種視覺效果的怪圈。這很容易導(dǎo)致大量的性能問題,為了獲得***的性能,我們必須盡量減少Overdraw的情況發(fā)生。
幸運(yùn)的是,我們可以通過手機(jī)設(shè)置里面的開發(fā)者選項(xiàng),打開Show GPU Overdraw的選項(xiàng),觀察UI上的Overdraw情況。
藍(lán)色,淡綠,淡紅,深紅代表了4種不同程度的Overdraw情況,我們的目標(biāo)就是盡量減少紅色Overdraw,看到更多的藍(lán)色區(qū)域。
6)Visualize and Fix Overdraw - Quiz & Solution
這里舉了一個(gè)例子,通過XML文件可以看到有好幾處非必需的background。通過把XML中非必需的background移除之后,可以顯著減少布局的過度繪制。其中一個(gè)比較有意思的地方是:針對(duì)ListView中的Avatar ImageView的設(shè)置,在getView的代碼里面,判斷是否獲取到對(duì)應(yīng)的Bitmap,在獲取到Avatar的圖像之后,把ImageView的Background設(shè)置為Transparent,只有當(dāng)圖像沒有獲取到的時(shí)候才設(shè)置對(duì)應(yīng)的Background占位圖片,這樣可以避免因?yàn)榻oAvatar設(shè)置背景圖而導(dǎo)致的過度渲染。
總結(jié)一下,優(yōu)化步驟如下:
移除Window默認(rèn)的Background
移除XML布局文件中非必需的Background
按需顯示占位背景圖片
7)ClipRect & QuickReject
前面有提到過,對(duì)不可見的UI組件進(jìn)行繪制更新會(huì)導(dǎo)致Overdraw。例如Nav Drawer從前置可見的Activity滑出之后,如果還繼續(xù)繪制那些在Nav Drawer里面不可見的UI組件,這就導(dǎo)致了Overdraw。為了解決這個(gè)問題,Android系統(tǒng)會(huì)通過避免繪制那些完全不可見的組件來盡量減少Overdraw。那些Nav Drawer里面不可見的View就不會(huì)被執(zhí)行浪費(fèi)資源。
但是不幸的是,對(duì)于那些過于復(fù)雜的自定義的View(通常重寫了onDraw方法),Android系統(tǒng)無法檢測在onDraw里面具體會(huì)執(zhí)行什么操作,系統(tǒng)無法監(jiān)控并自動(dòng)優(yōu)化,也就無法避免Overdraw了。但是我們可以通過canvas.clipRect()來幫助系統(tǒng)識(shí)別那些可見的區(qū)域。這個(gè)方法可以指定一塊矩形區(qū)域,只有在這個(gè)區(qū)域內(nèi)才會(huì)被繪制,其他的區(qū)域會(huì)被忽視。這個(gè)API可以很好的幫助那些有多組重疊組件的自定義View來控制顯示的區(qū)域。同時(shí)clipRect方法還可以幫助節(jié)約CPU與GPU資源,在clipRect區(qū)域之外的繪制指令都不會(huì)被執(zhí)行,那些部分內(nèi)容在矩形區(qū)域內(nèi)的組件,仍然會(huì)得到繪制。
除了clipRect方法之外,我們還可以使用canvas.quickreject()來判斷是否沒和某個(gè)矩形相交,從而跳過那些非矩形區(qū)域內(nèi)的繪制操作。
8)Apply clipRect and quickReject - Quiz & Solution
上面的示例圖中顯示了一個(gè)自定義的View,主要效果是呈現(xiàn)多張重疊的卡片。這個(gè)View的onDraw方法如下圖所示:
打開開發(fā)者選項(xiàng)中的顯示過度渲染,可以看到我們這個(gè)自定義的View部分區(qū)域存在著過度繪制。那么是什么原因?qū)е逻^度繪制的呢?
9)Fixing Overdraw with Canvas API
下面的代碼顯示了如何通過clipRect來解決自定義View的過度繪制,提高自定義View的繪制性能:
下面是優(yōu)化過后的效果:
10)Layouts, Invalidations and Perf
Android需要把XML布局文件轉(zhuǎn)換成GPU能夠識(shí)別并繪制的對(duì)象。這個(gè)操作是在DisplayList的幫助下完成的。DisplayList持有所有將要交給GPU繪制到屏幕上的數(shù)據(jù)信息。
在某個(gè)View***次需要被渲染時(shí),Display List會(huì)因此被創(chuàng)建,當(dāng)這個(gè)View要顯示到屏幕上時(shí),我們會(huì)執(zhí)行GPU的繪制指令來進(jìn)行渲染。
如果View的Property屬性發(fā)生了改變(例如移動(dòng)位置),我們就僅僅需要Execute Display List就夠了。
然而如果你修改了View中的某些可見組件的內(nèi)容,那么之前的DisplayList就無法繼續(xù)使用了,我們需要重新創(chuàng)建一個(gè)DisplayList并重新執(zhí)行渲染指令更新到屏幕上。
請(qǐng)注意:任何時(shí)候View中的繪制內(nèi)容發(fā)生變化時(shí),都會(huì)需要重新創(chuàng)建DisplayList,渲染DisplayList,更新到屏幕上等一系列操作。這個(gè)流程的表現(xiàn)性能取決于你的View的復(fù)雜程度,View的狀態(tài)變化以及渲染管道的執(zhí)行性能。舉個(gè)例子,假設(shè)某個(gè)Button的大小需要增大到目前的兩倍,在增大Button大小之前,需要通過父View重新計(jì)算并擺放其他子View的位置。修改View的大小會(huì)觸發(fā)整個(gè)HierarcyView的重新計(jì)算大小的操作。如果是修改View的位置則會(huì)觸發(fā)HierarchView重新計(jì)算其他View的位置。如果布局很復(fù)雜,這就會(huì)很容易導(dǎo)致嚴(yán)重的性能問題。
11)Hierarchy Viewer: Walkthrough
Hierarchy Viewer可以很直接的呈現(xiàn)布局的層次關(guān)系,視圖組件的各種屬性。 我們可以通過紅,黃,綠三種不同的顏色來區(qū)分布局的Measure,Layout,Executive的相對(duì)性能表現(xiàn)如何。
12)Nested Hierarchies and Performance
提升布局性能的關(guān)鍵點(diǎn)是盡量保持布局層級(jí)的扁平化,避免出現(xiàn)重復(fù)的嵌套布局。例如下面的例子,有2行顯示相同內(nèi)容的視圖,分別用兩種不同的寫法來實(shí)現(xiàn),他們有著不同的層級(jí)。
下圖顯示了使用2種不同的寫法,在Hierarchy Viewer上呈現(xiàn)出來的性能測試差異:
13)Optimizing Your Layout
下圖舉例演示了如何優(yōu)化ListItem的布局,通過RelativeLayout替代舊方案中的嵌套LinearLayout來優(yōu)化布局。
當(dāng)前標(biāo)題:Android性能優(yōu)化之渲染篇
鏈接分享:http://fisionsoft.com.cn/article/dpjjjgo.html


咨詢
建站咨詢
