1.前言
(1)岛抄、 CPU: 中央處理器,它集成了運算,緩沖,控制等單元,包括繪圖功能.CPU將對象處理為多維圖形,紋理(Bitmaps夫椭、Drawables等都是一起打包到統(tǒng)一的紋理).
(2)蹭秋、GPU:一個類似于CPU的專門用來處理Graphics的處理器, 作用用來幫助加快格柵化操作,當然,也有相應的緩存數據(例如緩存已經光柵化過的bitmap等)機制仁讨。
(3)洞豁、 OpenGL ES是手持嵌入式設備的3DAPI,跨平臺的、功能完善的2D和3D圖形應用程序接口API,有一套固定渲染管線流程. 附相關OpenGL渲染流程資料锐墙、OpenGL ES使用
(4)长酗、 DisplayList 在Android把XML布局文件轉換成GPU能夠識別并繪制的對象夺脾。這個操作是在DisplayList的幫助下完成的咧叭。DisplayList持有所有將要交給GPU繪制到屏幕上的數據信息。
(5)吉挣、 格柵化 是 將圖片等矢量資源,轉化為一格格像素點的像素圖,顯示到屏幕上睬魂。
(6)、 垂直同步VSYNC:讓顯卡的運算和顯示器刷新率一致以穩(wěn)定輸出的畫面質量商佛。它告知GPU在載入新幀之前良姆,要等待屏幕繪制完成前一幀歇盼。下面的三張圖分別是GPU和硬件同步所發(fā)生的情況,Refresh Rate:屏幕一秒內刷新屏幕的次數,由硬件決定,例如60Hz.而Frame Rate:GPU一秒繪制操作的幀數,單位是30fps,正常情況過程圖如下.
2.渲染機制介紹
(1)渲染流程線
UI對象—->CPU處理為多維圖形,紋理 —–通過OpeGL ES接口調用GPU—-> GPU對圖進行光柵化(Frame Rate ) —->硬件時鐘(Refresh Rate)—-垂直同步—->投射到屏幕
(2)渲染時間線
Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(1000ms/60=16.66ms)伯复,觸發(fā)對UI進行渲染啸如, 如果每次渲染都成功氮惯,這樣就能夠達到流暢的畫面所需要的60fps,為了能夠實現(xiàn)60fps帘不,這意味著計算渲染的大多數操作都必須在16ms內完成寞焙。
I辽狈、正常情況
II刮萌、渲染超時,計算渲染時間超過16ms
當這一幀畫面渲染時間超過16ms的時候,垂直同步機制會讓顯示器硬件 等待GPU完成柵格化渲染操作,
這樣會讓這一幀畫面,多停留了16ms,甚至更多.這樣就這造成了 用戶看起來 畫面停頓.
當GPU渲染速度過慢,就會導致如下情況,某些幀顯示的畫面內容就會與上一幀的畫面相同
3.渲染時會出現(xiàn)的問題
(1) GPU過度繪制
GPU的繪制過程,就跟刷墻一樣,一層層的進行,16ms刷一次.這樣就會造成,圖層覆蓋的現(xiàn)象,即無用的圖層還被繪制在底層,造成不必要的浪費.
(2)過度繪制查看工具
在手機端的開發(fā)者選項里,有OverDraw監(jiān)測工具,調試GPU過度繪制工具,
其中顏色代表渲染的圖層情況,分別代表1層,2層,3層,4層覆蓋.
手機的Monitor GPU Rendering
(3)計算渲染的耗時
任何時候View中的繪制內容發(fā)生變化時畜侦,都會重新執(zhí)行創(chuàng)建DisplayList旋膳,渲染DisplayList验懊,更新到屏幕上等一 系列操作义图。這個流程的表現(xiàn)性能取決于你的View的復雜程度碱工,View的狀態(tài)變化以及渲染管道的執(zhí)行性能。
舉個例子,當View的大小發(fā)生改變,DisplayList就會重新創(chuàng)建,然后再渲染,而當View發(fā)生位移,則DisplayList不會重新創(chuàng)建,而是執(zhí)行重新渲染的操作酗昼。
當你的View過于復雜,操作又過于復雜,就會計算渲染時間超過16ms,產生卡頓問題麻削。
(4)渲染耗時呈現(xiàn)工具
工具中,不同手機呈現(xiàn)方式可能會有差別.分別關于StatusBar,NavBar叠荠,激活的程序Activity區(qū)域的GPU Rending信息俺祠。激活的程序Activity區(qū)域的GPU Rending信息。
界面上會滾動顯示垂直的柱狀圖來表示每幀畫面所需要渲染的時間蜘渣,柱狀圖越高表示花費的渲染時間越長。
中間有一根綠色的橫線拾碌,代表16ms街望,我們需要確保每一幀花費的總時間都低于這條橫線,這樣才能夠避免出現(xiàn)卡頓的問題防症。
每一條柱狀線都包含三部分,
藍色代表測量繪制Display List的時間奈嘿,
紅色代表OpenGL渲染Display List所需要的時間裙犹,
黃色代表CPU等待GPU處理的時間衔憨。
4. 如何促進優(yōu)化
有人會說這些小地方,不值得優(yōu)化.但是當你用的是低配機器,內存到飽和,CPU運算到達飽和,就像一個界面要做很多交互,繪制,加載圖片,請求網絡.后,一個小問題就會導致頁面卡頓,OOM,項目崩潰.
(1)Android系統(tǒng)已經對它優(yōu)化
在Android里面那些由主題所提供的資源,例如Bitmaps平项,Drawables都是一起打包到統(tǒng)一的Texture紋理當中赫舒,然后再傳遞到 GPU里面悍及,這意味著每次你需要使用這些資源的時候,都是直接從紋理里面進行獲取渲染的接癌。
(2)要做的優(yōu)化
扁平化處理,防止過度繪制OverDraw
(3)每一個layout的最外層父容器 是否需要?
(4)布局層級優(yōu)化
進行檢測時,可能會讓多種檢測工具沖突,用Android Device Monitor的時候,最好關閉相關手機上的開發(fā)者檢測工具開關.
查看自己的布局心赶,深的層級,是否可以做優(yōu)化.
渲染比較耗時(顏色就能看出來),想辦法能否減少層級以及優(yōu)化每一個View的渲染時間.
(5)Hierarchy Viewer工具**
他是查看耗時情況,和布局樹的深度的工具.
(6)圖片選擇
Android的界面能用png最好是用png了,因為32位的png顏色過渡平滑且支持透明缺猛。jpg是像素化壓縮過的圖片缨叫,質量已經下降了,再拿來做9path的按鈕和平鋪拉伸的控件必然慘不忍睹荔燎,要盡量避免耻姥。
(7)清理不必要的背景
(8)當背景無法避免,盡量用Color.TRANSPARENT
因為透明色
Color.TRANSPARENT
是不會被渲染的,他是透明的.
//優(yōu)化前
//優(yōu)化前: 當圖片不為空,ImageView加載圖片,然后統(tǒng)一設置背景
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)化后:當圖片不為空,ImageView加載圖片,并設置背景為TRANSPARENT;
//當圖片為空,ImageView加載TRANSPARENT,然后設置背景為無照片背景
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);
}
(9)優(yōu)化自定義View的計算
View中的方法OnMeasure,OnLayout,OnDraw.在我們自定義View起到了決定作用,我們要學會研究其中的優(yōu)化方法.
學會裁剪掉View的覆蓋部分,增加cpu的計算量,來優(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.總結
性能優(yōu)化其實不僅僅是一種技術,而是一種思想,你只聽過它的高大上,卻不知道它其實就是各個細節(jié)處的深入研究和處理.
當然,有的時候也需要自己進行權衡效果和性能,根據需求進行選擇.
所以在平時的開發(fā)過程中,養(yǎng)成良好的思考習慣,是第一步~
代碼的思想:
(1)你的代碼是不是多余?
(2)你的對象有沒有必要在循環(huán)中創(chuàng)建?
(3)你的計算方法是不是最優(yōu)?
畫界面的考慮:
(1)布局是否有背景?
(2)是否可以刪掉多余的布局?
(3)自定義View是否進行了裁剪處理?
(4)布局是否扁平化,移除非必需的UI組?
最后,最后加油吧!騷年,你絕對是一個有逼格的程序猿K芩场!!