UI繪制優(yōu)化
一.CPU與GPU工作流程
? ?cpu:中央處理器(用于計(jì)算)
? ?gpu:圖形處理器(用于顯示)
? CPU 的任務(wù)繁多,做邏輯計(jì)算外,還要做內(nèi)存管理唱矛、顯示操作,因此在實(shí)際運(yùn)算的時(shí)候性能? ? ? 會(huì)大打折扣井辜,在沒(méi)有 GPU 的時(shí)代绎谦,不能顯示復(fù)雜的圖形,其運(yùn)算速度遠(yuǎn)跟不上今天復(fù)雜三維? ? 游戲的要求粥脚。即使 CPU的工作頻率超過(guò) 2GHz 或更高窃肠,對(duì)它繪制圖形提高也不大。這時(shí) GPU? ? 的設(shè)計(jì)就出來(lái)了
黃色的 Control 為控制器刷允,用于協(xié)調(diào)控制整個(gè) CPU 的運(yùn)行冤留,包括取出指令、控制其他模塊的運(yùn)行等树灶;
綠色的 ALU ( Arithmetic Logic Unit )是算術(shù)邏輯單元纤怒,用于進(jìn)行數(shù)學(xué)、邏輯運(yùn)算天通;
橙色的 Cache 和 DRAM 分別為緩存和 RAM 泊窘,用于存儲(chǔ)信息。
從結(jié)構(gòu)圖可以看出像寒, CPU 的控制器較為復(fù)雜烘豹,而 ALU 數(shù)量較少。因此 CPU 擅長(zhǎng)各種復(fù)雜
的邏輯運(yùn)算诺祸,但不擅長(zhǎng)數(shù)學(xué)尤其是浮點(diǎn)運(yùn)算携悯。
60Hz 刷新頻率由來(lái)(1秒60幀圖片,一幀代表一張圖片)
Android 系統(tǒng)每隔 16ms 發(fā)出 VSYNC (垂直同步信號(hào))信號(hào) (1000ms/60=16.66ms) 筷笨,觸發(fā)對(duì) UI 進(jìn)行渲染憔鬼, 如果每次渲染都成功這樣就能夠達(dá)到流暢的畫(huà)面所需要的 60fps 龟劲,為了能夠?qū)崿F(xiàn) 60fps ,這意味著計(jì)算渲染的大多數(shù)操作都必須在 16ms 內(nèi)完成逊彭。
12 fps :由于人類眼睛的特殊生理結(jié)構(gòu),如果所看畫(huà)面之幀率高于每秒約 10-12 幀的時(shí)候构订,就會(huì)認(rèn)為是連貫的
24 fps :有聲電影的拍攝及播放幀率均為每秒 24 幀侮叮,對(duì)一般人而言已算可接受
30 fps :早期的高動(dòng)態(tài)電子游戲,幀率少于每秒 30 幀的話就會(huì)顯得不連貫悼瘾,這是因?yàn)闆](méi)有動(dòng)態(tài)模糊使流暢度降低
60 fps 在與手機(jī)交互過(guò)程中囊榜,如觸摸和反饋 60 幀以下人是能感覺(jué)出來(lái)的。 60 幀以上不能察覺(jué)
變化當(dāng)幀率低于 60 fps 時(shí)感覺(jué)的畫(huà)面的卡頓和遲滯現(xiàn)象
卡頓原理分析
當(dāng)這一幀畫(huà)面渲染時(shí)間超過(guò)16ms的時(shí)候亥宿,垂直同步機(jī)制會(huì)讓顯示器硬件等待GPU完成柵格化渲染操作卸勺,這樣會(huì)讓這一幀畫(huà)面,多停留了16ms甚至更多烫扼,這樣就造成了用戶看起來(lái)畫(huà)面停頓曙求。(也可以理解為丟幀,看電影的時(shí)候映企,有的畫(huà)面出現(xiàn)卡頓灰暗屏就是這個(gè)原因)
二.什么是過(guò)度繪制
GPU的繪制就跟刷墻一樣,一層一層的進(jìn)行悟狱,16ms刷一次,這樣就會(huì)造成圖層覆蓋的現(xiàn)象堰氓,即無(wú)用的圖層還被繪制到底層挤渐,造成不必要的浪費(fèi)。
GPU過(guò)度繪制的幾種情況
1.自定義控件中双絮,onDraw()做了過(guò)多重復(fù)繪制
2.布局層次太深浴麻,重疊性太強(qiáng),用戶看不到的區(qū)域GPU也會(huì)渲染囤攀,導(dǎo)致耗時(shí)增加
過(guò)度繪制查看工具
在手機(jī)端的開(kāi)發(fā)者選項(xiàng)里软免,有OverDraw的監(jiān)視工具,測(cè)試GPU過(guò)度繪制工具焚挠,其中顏色代表渲染的圖層情況或杠,分別代表1層,2層宣蔚,3層向抢,4層
藍(lán)色:過(guò)度繪制一次 無(wú)過(guò)度繪制
綠色:過(guò)度繪制兩次
淡紅:過(guò)度繪制三次
深紅:過(guò)度繪制四次
它們代表了4種不同程度OverDraw情況,我們的目標(biāo)就是盡量減少紅色胚委,看到更多的藍(lán)色區(qū)域
那 Android 系統(tǒng)有沒(méi)有給我們做優(yōu)化的操作呢
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 組件的越來(lái)越豐富,有了更多演變的形態(tài)凤壁。例如顯示圖片的時(shí)候吩屹,需要先經(jīng)過(guò) CPU 的計(jì)算加載到內(nèi)存中,然后傳遞給 GPU 進(jìn)行渲染拧抖。文字的顯示比較復(fù)雜煤搜,需要先經(jīng)過(guò) CPU 換算成紋理,然后交給 GPU 進(jìn)行渲染唧席,返回到 CPU 繪制單個(gè)字符的時(shí)候擦盾,再重新引用經(jīng)過(guò) GPU 渲染的內(nèi)容。動(dòng)畫(huà)則存在一個(gè)更加復(fù)雜的操作流程淌哟。為了能夠使得 App 流暢厌衙,我們需要在每幀 16ms 以內(nèi)處理完所有的 CPU 與 GPU 的計(jì)算,繪制绞绒,渲染等等操作婶希。
過(guò)度繪制優(yōu)化(主要減少GPU工作量)
1.減少背景重復(fù)
? ? ? ? ? ? ? ? 注意主題中的設(shè)置:(1)去掉單個(gè)activity的主題設(shè)置的屬性可以在setContentView 之前getWindow().setBackgroundDrawable(null);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2)去掉所有activity主題設(shè)置中的屬性直接在styles.xml中設(shè)置<item? ? ? name="android:windowBackground">@null</item>
2.使用裁減減少控件之間的重合部分
三.布局的優(yōu)化(主要減少CPU工作量)
常用工具
Android/sdk/tools/bin/ui automator viewer.bat
Android\sdk\tools\monitor.bat
Device Monitor窗口中Hierarchy view
? ? ? ? ?三個(gè)點(diǎn)也是代表著View的Measure, Layout和Draw。
? ? ? ? 綠: 表示該View的此項(xiàng)性能比該View Tree中超過(guò)50%的View都要快蓬衡;例如,代表Measure的 是綠點(diǎn),意味著這個(gè)視圖的測(cè)量時(shí)間快于樹(shù)中的視圖對(duì)象的50%喻杈。
? ? ? ? 黃: 表示該View的此項(xiàng)性能比該View Tree中超過(guò)50%的View都要慢;
? ? ? ? ?紅: 表示該View的此項(xiàng)性能是View Tree中最慢的狰晚;筒饰。
注意點(diǎn):
1.能在一個(gè)平面顯示的內(nèi)容,盡量只用一個(gè)容器
2.盡可能把相同的容器合并merge
3.能復(fù)用的代碼壁晒,用include處理瓷们,可以減少GPU重復(fù)工作