渲染優(yōu)化

文章來(lái)源:
http://wuxiaolong.me/2017/03/26/Rendering/
http://m.itdecent.cn/p/989ce9eb7af8
hz:每秒刷新的次數(shù)

著名的“16ms”原則:
我們通常都會(huì)提到60fps(Frame Per Second)與16ms,可是知道為何會(huì)是以程序是否達(dá)到60fps來(lái)作為App性能的衡量標(biāo)準(zhǔn)嗎?
60fps:人眼與大腦之間的協(xié)作無(wú)法感知超過(guò)60fps的畫面更新。
*16ms:因?yàn)锳ndroid設(shè)定的刷新率是60fps,也就是每秒60幀,即16ms=1000/60Hz
Android系統(tǒng)每隔16ms會(huì)發(fā)出VSYNC信號(hào)重繪我們的界面。

就像這樣:


image.png

如果你的某個(gè)操作花費(fèi)時(shí)間是24ms,系統(tǒng)在得到VSYNC信號(hào)的時(shí)候就無(wú)法進(jìn)行正常渲染,這樣就發(fā)生了丟幀現(xiàn)象。那么用戶在32ms內(nèi)看到的會(huì)是同一幀畫面。


image.png

Overdraw(過(guò)度繪制)是指系統(tǒng)在單個(gè)渲染幀中多次繪制屏幕上的像素。例如,如果我們有一堆堆疊的UI卡,不可見的UI也在做繪制的操作,這樣會(huì)浪費(fèi)大量的CPU和GPU資源。
渲染操作通常依賴于兩個(gè)核心組件:CPU與GPU。CPU負(fù)責(zé)包括Measure,Layout,Record,Execute的計(jì)算操作,GPU負(fù)責(zé)Rasterization(柵格化)操作

如何檢測(cè)?

  • Show GPU Overdraw
    設(shè)置 -> 開發(fā)者選項(xiàng) -> 調(diào)試GPU過(guò)度繪制 ->顯示過(guò)度繪制區(qū)域。
    對(duì)比一張Overdraw的參考圖,分別有藍(lán)色,淡綠,淡紅,深紅代表了4種不同程度的Overdraw情況:


    image.png

    藍(lán)色,淡綠,淡紅,深紅代表了4種不同程度的Overdraw情況,我們的目標(biāo)就是盡量減少紅色Overdraw,看到更多的藍(lán)色區(qū)域。

Overdraw有時(shí)候是因?yàn)槟愕腢I布局存在大量重疊的部分,還有的時(shí)候是因?yàn)榉潜仨毜闹丿B背景。例如某個(gè)Activity有一個(gè)背景,然后里面的Layout又有自己的背景,同時(shí)子View又分別有自己的背景。僅僅是通過(guò)移除非必須的背景圖片,這就能夠減少大量的紅色Overdraw區(qū)域,增加藍(lán)色區(qū)域的占比。這一措施能夠顯著提升程序性能。

  • Profile GPU Rendering
    打開Profile GPU Rendering,顯示每幀畫面所需要渲染的時(shí)間。
    設(shè)置 -> 開發(fā)者選項(xiàng) -> GPU呈現(xiàn)模式分析 -> 在屏幕上顯示為條形圖
image.png

界面上會(huì)滾動(dòng)顯示垂直的柱狀圖來(lái)表示每幀畫面所需要渲染的時(shí)間,柱狀圖越高表示花費(fèi)的渲染時(shí)間越長(zhǎng)。中間有一根綠色的橫線,代表16ms,我們需要確保每一幀花費(fèi)的總時(shí)間都低于這條橫線,這樣才能夠避免出現(xiàn)卡頓的問題。

  • Hierarchy Viewer
    用Hierarchy Viewer工具檢查Activity中的布局是否過(guò)于復(fù)雜
    Tools -> Android -> Android Device Monitor。


    image.png

    image.png
image.png

其實(shí)中帶有紅色或黃色的點(diǎn)代表速度較慢的View。

優(yōu)化方案:

  • 刪除布局中不必要的背景屬性
  • 盡量減少布局的層級(jí)
    來(lái)源:https://blog.csdn.net/xyz_lmn/article/details/14524567
    減少視圖層級(jí)<merge />
    <merge/>標(biāo)簽在UI的結(jié)構(gòu)優(yōu)化中起著非常重要的作用,它可以刪減多余的層級(jí),優(yōu)化UI。<merge/>多用于替換FrameLayout或者當(dāng)一個(gè)布局包含另一個(gè)時(shí),<merge/>標(biāo)簽消除視圖層次結(jié)構(gòu)中多余的視圖組。例如你的主布局文件是垂直布局,引入了一個(gè)垂直布局的include,這是如果include布局使用的LinearLayout就沒意義了,使用的話反而減慢你的UI表現(xiàn)。這時(shí)可以使用<merge/>標(biāo)簽優(yōu)化。
<merge xmlns:android="http://schemas.android.com/apk/res/android">
 
    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/add"/>
 
    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/delete"/>
 
</merge>

現(xiàn)在,當(dāng)你添加該布局文件時(shí)(使用<include />標(biāo)簽),系統(tǒng)忽略<merge />節(jié)點(diǎn)并且直接添加兩個(gè)Button。

  • 需要時(shí)使用<ViewStub />
    <ViewStub />標(biāo)簽最大的優(yōu)點(diǎn)是當(dāng)你需要時(shí)才會(huì)加載,使用他并不會(huì)影響UI初始化時(shí)的性能。各種不常用的布局想進(jìn)度條、顯示錯(cuò)誤消息等可以使用<ViewStub />標(biāo)簽,以減少內(nèi)存使用量,加快渲染速度。<ViewStub />是一個(gè)不可見的,大小為0的View。<ViewStub />標(biāo)簽使用如下:

<ViewStub
    android:id="@+id/stub_import"
    android:inflatedId="@+id/panel_import"
    android:layout="@layout/progress_overlay"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom" />

當(dāng)你想加載布局時(shí),可以使用下面其中一種方法:


((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();

當(dāng)調(diào)用inflate()函數(shù)的時(shí)候,ViewStub被引用的資源替代,并且返回引用的view。 這樣程序可以直接得到引用的view而不用再次調(diào)用函數(shù)findViewById()來(lái)查找了。
注:ViewStub目前有個(gè)缺陷就是還不支持 <merge /> 標(biāo)簽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容