深入Android渲染機(jī)制

1.知識(shí)儲(chǔ)備

  • CPU: 中央處理器,它集成了運(yùn)算,緩沖,控制等單元,包括繪圖功能.CPU將對(duì)象處理為多維圖形,紋理(Bitmaps、Drawables等都是一起打包到統(tǒng)一的紋理).

  • GPU:一個(gè)類似于CPU的專門用來處理Graphics的處理器, 作用用來幫助加快柵格化操作,當(dāng)然,也有相應(yīng)的緩存數(shù)據(jù)(例如緩存已經(jīng)光柵化過的bitmap等)機(jī)制。

  • OpenGL ES是手持嵌入式設(shè)備的3DAPI,跨平臺(tái)的、功能完善的2D和3D圖形應(yīng)用程序接口API,有一套固定渲染管線流程. 附相關(guān)OpenGL渲染流程資料

  • DisplayList 在Android把XML布局文件轉(zhuǎn)換成GPU能夠識(shí)別并繪制的對(duì)象。這個(gè)操作是在DisplayList的幫助下完成的。DisplayList持有所有將要交給GPU繪制到屏幕上的數(shù)據(jù)信息。

  • 柵格化 是 將圖片等矢量資源,轉(zhuǎn)化為一格格像素點(diǎn)的像素圖,顯示到屏幕上,過程圖如下.

柵格化操作
  • 垂直同步VSYNC:讓顯卡的運(yùn)算和顯示器刷新率一致以穩(wěn)定輸出的畫面質(zhì)量。它告知GPU在載入新幀之前,要等待屏幕繪制完成前一幀。下面的三張圖分別是GPU和硬件同步所發(fā)生的情況,Refresh Rate:屏幕一秒內(nèi)刷新屏幕的次數(shù),由硬件決定,例如60Hz.而Frame Rate:GPU一秒繪制操作的幀數(shù),單位是30fps,正常情況過程圖如下.
正常情況

2.渲染機(jī)制分析

渲染流程線

UI對(duì)象---->CPU處理為多維圖形,紋理 -----通過OpeGL ES接口調(diào)用GPU----> GPU對(duì)圖進(jìn)行光柵化(Frame Rate ) ---->硬件時(shí)鐘(Refresh Rate)----垂直同步---->投射到屏幕

圖片名稱

渲染時(shí)間線

Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(hào)(1000ms/60=16.66ms),觸發(fā)對(duì)UI進(jìn)行渲染, 如果每次渲染都成功,這樣就能夠達(dá)到流暢的畫面所需要的60fps,為了能夠?qū)崿F(xiàn)60fps,這意味著計(jì)算渲染的大多數(shù)操作都必須在16ms內(nèi)完成。

正常情況

這里寫圖片描述

渲染超時(shí),計(jì)算渲染時(shí)間超過16ms

當(dāng)這一幀畫面渲染時(shí)間超過16ms的時(shí)候,垂直同步機(jī)制會(huì)讓顯示器硬件 等待GPU完成柵格化渲染操作,
這樣會(huì)讓這一幀畫面,多停留了16ms,甚至更多.這樣就這造成了 用戶看起來 畫面停頓.

當(dāng)GPU渲染速度過慢,就會(huì)導(dǎo)致如下情況,某些幀顯示的畫面內(nèi)容就會(huì)與上一幀的畫面相同

GPU超時(shí)情況

3.渲染時(shí)會(huì)出現(xiàn)的問題

GPU過度繪制

GPU的繪制過程,就跟刷墻一樣,一層層的進(jìn)行,16ms刷一次.這樣就會(huì)造成,圖層覆蓋的現(xiàn)象,即無用的圖層還被繪制在底層,造成不必要的浪費(fèi).

這里寫圖片描述

過度繪制查看工具

在手機(jī)端的開發(fā)者選項(xiàng)里,有OverDraw監(jiān)測工具,調(diào)試GPU過度繪制工具,
其中顏色代表渲染的圖層情況,分別代表1層,2層,3層,4層覆蓋.

這里寫圖片描述

我的魅族手機(jī)的Monitor GPU Rendering

這里寫圖片描述

計(jì)算渲染的耗時(shí)

任何時(shí)候View中的繪制內(nèi)容發(fā)生變化時(shí),都會(huì)重新執(zhí)行創(chuàng)建DisplayList,渲染DisplayList,更新到屏幕上等一 系列操作。這個(gè)流程的表現(xiàn)性能取決于你的View的復(fù)雜程度,View的狀態(tài)變化以及渲染管道的執(zhí)行性能。

舉個(gè)例子,當(dāng)View的大小發(fā)生改變,DisplayList就會(huì)重新創(chuàng)建,然后再渲染,而當(dāng)View發(fā)生位移,則DisplayList不會(huì)重新創(chuàng)建,而是執(zhí)行重新渲染的操作.

當(dāng)你的View過于復(fù)雜,操作又過于復(fù)雜,就會(huì)計(jì)算渲染時(shí)間超過16ms,產(chǎn)生卡頓問題.

渲染耗時(shí)呈現(xiàn)工具

工具中,不同手機(jī)呈現(xiàn)方式可能會(huì)有差別.分別關(guān)于StatusBar,NavBar,激活的程序Activity區(qū)域的GPU Rending信息。激活的程序Activity區(qū)域的GPU Rending信息。

界面上會(huì)滾動(dòng)顯示垂直的柱狀圖來表示每幀畫面所需要渲染的時(shí)間,柱狀圖越高表示花費(fèi)的渲染時(shí)間越長。

中間有一根綠色的橫線,代表16ms,我們需要確保每一幀花費(fèi)的總時(shí)間都低于這條橫線,這樣才能夠避免出現(xiàn)卡頓的問題。

這里寫圖片描述

每一條柱狀線都包含三部分,
藍(lán)色代表測量繪制Display List的時(shí)間,
紅色代表OpenGL渲染Display List所需要的時(shí)間,
黃色代表CPU等待GPU處理的時(shí)間。

這里寫圖片描述

4.如何優(yōu)化

有人會(huì)說這些小地方,不值得優(yōu)化.但是當(dāng)你用的是低配機(jī)器,內(nèi)存到飽和,CPU運(yùn)算到達(dá)飽和,就像一個(gè)界面要做很多交互,繪制,加載圖片,請(qǐng)求網(wǎng)絡(luò).后,一個(gè)小問題就會(huì)導(dǎo)致頁面卡頓(就像我手機(jī)的淘寶客戶端...),OOM,項(xiàng)目崩潰.

是的,這就是力量~

Android系統(tǒng)已經(jīng)對(duì)它優(yōu)化

在Android里面那些由主題所提供的資源,例如Bitmaps,Drawables都是一起打包到統(tǒng)一的Texture紋理當(dāng)中,然后再傳遞到 GPU里面,這意味著每次你需要使用這些資源的時(shí)候,都是直接從紋理里面進(jìn)行獲取渲染的。

我們要做的優(yōu)化

扁平化處理,防止過度繪制OverDraw

**1.每一個(gè)layout的最外層父容器 是否需要? **

這里寫圖片描述

**2.布局層級(jí)優(yōu)化 **

進(jìn)行檢測時(shí),可能會(huì)讓多種檢測工具沖突,用Android Device Monitor的時(shí)候,最好關(guān)閉相關(guān)手機(jī)上的開發(fā)者檢測工具開關(guān).
查看自己的布局,深的層級(jí),是否可以做優(yōu)化.
渲染比較耗時(shí)(顏色就能看出來),想辦法能否減少層級(jí)以及優(yōu)化每一個(gè)View的渲染時(shí)間.

Hierarchy Viewer工具

他是查看耗時(shí)情況,和布局樹的深度的工具.

這里寫圖片描述

3.圖片選擇

Android的界面能用png最好是用png了,因?yàn)?strong>32位的png顏色過渡平滑且支持透明。jpg是像素化壓縮過的圖片,質(zhì)量已經(jīng)下降了,再拿來做9path的按鈕和平鋪拉伸的控件必然慘不忍睹,要盡量避免。

對(duì)于顏色繁雜的,照片墻紙之類的圖片(應(yīng)用的啟動(dòng)畫面喜歡搞這種),那用jpg是最好不過了,這種圖片壓縮前壓縮后肉眼分辨幾乎不計(jì),如果保存成png體積將是jpg的幾倍甚至幾十倍,嚴(yán)重浪費(fèi)體積。

4.清理不必要的背景

這里寫圖片描述

5.當(dāng)背景無法避免,盡量用Color.TRANSPARENT

因?yàn)橥该魃?code>Color.TRANSPARENT是不會(huì)被渲染的,他是透明的.


//優(yōu)化前
//優(yōu)化前: 當(dāng)圖片不為空,ImageView加載圖片,然后統(tǒng)一設(shè)置背景
Bean bean=list.get(i);
 if (bean.img == 0) {
            Picasso.with(getContext()).load(bean.img).into(holder.imageView);
        }
        chat_author_avatar.setBackgroundColor(bean.backPic);

//優(yōu)化后
//優(yōu)化后:當(dāng)圖片不為空,ImageView加載圖片,并設(shè)置背景為TRANSPARENT;
//當(dāng)圖片為空,ImageView加載TRANSPARENT,然后設(shè)置背景為無照片背景
Bean bean=list.get(i);
 if (bean.img == 0) {
            Picasso.with(getContext()).load(android.R.color.transparent).into(holder.imageView);
            holder.imageView.setBackgroundColor(bean.backPic);
        } else {
            Picasso.with(getContext()).load(bean.img).into(holder.imageView);
            holder.imageView.setBackgroundColor(Color.TRANSPARENT);
        }

-------------對(duì)比結(jié)果--------------------


這里寫圖片描述

6.優(yōu)化自定義View的計(jì)算

View中的方法OnMeasure,OnLayout,OnDraw.在我們自定義View起到了決定作用,我們要學(xué)會(huì)研究其中的優(yōu)化方法.

學(xué)會(huì)裁剪掉View的覆蓋部分,增加cpu的計(jì)算量,來優(yōu)化GPU的渲染


  /**
     * Intersect the current clip with the specified rectangle, which is
     * expressed in local coordinates.
     *
     * @param left   The left side of the rectangle to intersect with the
     *               current clip
     * @param top    The top of the rectangle to intersect with the current clip
     * @param right  The right side of the rectangle to intersect with the
     *               current clip
     * @param bottom The bottom of the rectangle to intersect with the current
     *               clip
     * @return       true if the resulting clip is non-empty
     */
    public boolean clipRect(float left, float top, float right, float bottom) {
        return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom,
                Region.Op.INTERSECT.nativeInt);
    }


5.總結(jié)

性能優(yōu)化其實(shí)不僅僅是一種技術(shù),而是一種思想,你只聽過它的高大上,卻不知道它其實(shí)就是各個(gè)細(xì)節(jié)處的深入研究和處理.

當(dāng)然,有的時(shí)候也需要自己進(jìn)行權(quán)衡效果和性能,根據(jù)需求進(jìn)行選擇.

還有,Android Device Monitor 是個(gè)好東西~簡直就是性能優(yōu)化大本營,性能優(yōu)化的工具基本都在其中.

所以在平時(shí)的開發(fā)過程中,養(yǎng)成良好的思考習(xí)慣,是第一步~

寫代碼的時(shí)候要想:

1.你的代碼是不是多余?

2.你的對(duì)象有沒有必要在循環(huán)中創(chuàng)建?

3.你的計(jì)算方法是不是最優(yōu)?

畫界面的時(shí)候要想:

1.布局是否有背景?

2.是否可以刪掉多余的布局?

3.自定義View是否進(jìn)行了裁剪處理?

4.布局是否扁平化,移除非必需的UI組?

最后,Android Device Monitor 是個(gè)好東西~ 性能優(yōu)化的工具基本都在其中.

關(guān)于我:

我的github: https://github.com/ccj659/

我的簡書: 簡書地址傳送門

我的CSDN博客: http://blog.csdn.net/ccj659/article

我的上一篇性能優(yōu)化文章: 深入android內(nèi)存泄漏

QQ進(jìn)階交流群:570381965

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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