同樣附上我的github <a> https://github.com/BudSpore</a>
上一篇文章我們對UI的渲染機(jī)制有了簡單的了解,通過渲染原理我們知道UI渲染流程要在16ms內(nèi)完成础爬,本篇文章我將給大家講解Android性能優(yōu)化里面的一小部分內(nèi)容,給開發(fā)者們提供一些思路看蚜,其實(shí)造成性能問題還有很多,內(nèi)存泄露供炎,電量,線程阻塞碱茁,代碼低耦合......好在現(xiàn)在有不少的解決方案,阿里巴巴的雙11App流暢度做了極大的優(yōu)化墓贿,作者最近因為找工作,從中對阿里的Weex產(chǎn)生了濃厚的興趣聋袋,我會在后面的文章中再慢慢研究,不過Weex學(xué)習(xí)成本真是好大啊幽勒,感慨一下。
該文我們先從GPU分析啥容。屏幕顯示圖片的時候顷霹,需要先經(jīng)過CPU的計算加載到內(nèi)存中,然后傳遞給GPU進(jìn)行渲染淋淀。文字的顯示比較復(fù)雜,需要先經(jīng)過CPU換算成紋理,然后交給GPU進(jìn)行渲染炭臭,返回到CPU繪制單個字符的時候,再重新引用經(jīng)過GPU渲染的內(nèi)容鞋仍。動畫則存在一個更加復(fù)雜的操作流程,我們在追求華麗的視覺效果的時候凿试,會用到多層重疊視圖去實(shí)現(xiàn),這會導(dǎo)致性能上出現(xiàn)問題那婉。
<h3>UI渲染會遇到的問題</h3>
<h4>GPU的過度繪制</h4>
Overdraw(過度繪制)是屏幕上的某個像素在同一幀的時間內(nèi)被繪制了多次。在多層次的UI結(jié)構(gòu)里面盐类, 如果不可見的UI也在做繪制的操作,這就會導(dǎo)致某些像素區(qū)域被繪制了多次
圖像覆蓋現(xiàn)象會導(dǎo)致GPU繪制的過程中無用圖層繪制在底層在跳,造成不必要的浪費(fèi)隐岛。
我用的是三星手機(jī)(不是Note 7)猫妙,Android機(jī)大概按照以下步驟打開Show GPU Overrdraw:設(shè)置 -> 開發(fā)者選項 -> 調(diào)試GPU過度渲染--> 顯示過度渲染區(qū)域
然后就可以看到下圖:
我們看到了屏幕里多了不少帶顏色的框框割坠,我們對這些框框分析一下:
藍(lán)色,淡綠彼哼,粉湘今,深紅代表了4種不同程度的GPU過度繪制情況,
藍(lán)色: GPU過度繪制了 1倍敢朱。像素繪制了兩次摩瞎。大片的藍(lán)色還是可以接受的(若整個窗口是藍(lán)色的,可以擺脫一層)旗们。
綠色: GPU過度繪制了 2倍。像素繪制了三次蚪拦。中等大小的綠色區(qū)域是可以接受的但你應(yīng)該嘗試優(yōu)化、減少它們驰贷。
淡紅: GPU過度繪制了 3倍。像素繪制了四次括袒,小范圍可以接受。
深紅: GPU過度繪制了 4倍锹锰。像素繪制了五次或者更多。這是錯誤的恃慧,要修復(fù)它們。
我們的目標(biāo)就是盡量減少紅色Overdraw痢士,看到更多的藍(lán)色區(qū)域。
<h4>解決方案</h4>
- 移除Window默認(rèn)的Background
getWidow.setBackgroundDrawable(null); - 移除XML布局文件中非必需的Background
- 按需求顯示占位背景圖片
- 減少布局嵌套(扁平化的一個體現(xiàn)怠蹂,減少View數(shù)的深度,也就減少了View樹的遍歷時間易遣,渲染的時候,前后期的工作豆茫,總是按View樹結(jié)點(diǎn)來)
這些都是一些常識了,我簡單帶過澜薄。。 -
<h6>ClipRect</h6>
我們平時使用NavigationView的時候肤京,側(cè)滑出Nav Drawer,Nav Drawer里面不可見的View就不會被Overdraw。
Paste_Image.png
圖中橙色區(qū)域不會被重繪忘分。
一旦我們自定義View白修,重寫onDraw()方法妒峦,方法里對View的操作將會重繪兵睛,然而我們可以通過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)的組件哥桥,仍然會得到繪制
應(yīng)用場景:當(dāng)我們在自定義View的時候辙浑,可能會出現(xiàn)圖片重疊導(dǎo)致Overdraw泰讽,當(dāng)我們使用canvas.clipRect(),會提高性能已卸,另外,在onDraw方法里面盡量不要有耗時操作累澡,
- ViewStub(延遲化加載)
主要的應(yīng)用場景就比如說新聞App,打開某個界面愧哟,如果有網(wǎng)絡(luò)就展示內(nèi)容,沒有網(wǎng)絡(luò)就會提示出網(wǎng)絡(luò)連接出錯蕊梧,這個出錯提示就是ViewStub,在正確的條件下才會顯示出內(nèi)容肥矢。 - include(引入布局)
當(dāng)不同的界面有相同的UI元素的時候我們可以使用include標(biāo)簽,不過引入的布局還可能會被嵌套在LinearLayout,RelativeLayout里面甘改。所以引入merge標(biāo)簽。 - merge
在引入布局文件里面抵代,最外層可以用merge替代LinearLayout,RelativeLayout,這樣把子UI元素直接銜接在include位置荤牍。
另外RelativeLayout通常會對它們的子視圖進(jìn)行2次測量案腺,子視圖使用了layout_weight屬性的LinearLayout也會對它的子視圖進(jìn)行2次測量参淫;我們一般推薦使用RelativeLayout救湖,然而我們視項目具體問題具體分析涎才。