界面是 Android 應用中直接影響用戶體驗最關鍵的部分。若是代碼實現得很差,界面容易發生卡頓且致使應用佔用大量內存。作 ROM 的公司更不同,預裝的應用必定要很是流暢,這樣給客戶或用戶的第一感受就是快。又卡又慢的應用體驗,會影響客戶或用戶對產品的信心和評價,因此不可忽視。面試
Android系統要求每一幀都要在 16ms 內繪製完成,平滑的完成一幀意味着任何特殊的幀須要執行全部的渲染代碼(包括 framework 發送給 GPU 和 CPU 繪製到緩衝區的命令)都要在 16ms 內完成,保持流暢的體驗。這個速度容許系統在動畫和輸入事件的過程當中以約 60 幀每秒( 1秒 / 0.016幀每秒 = 62.5幀/秒 )的平滑幀率來渲染。網絡
若是你的應用沒有在 16ms 內完成這一幀的繪製,假設你花了 24ms 來繪製這一幀,那麼就會出現掉幀的狀況。架構
系統準備將新的一幀繪製到屏幕上,可是這一幀並無準備好,全部就不會有繪製操做,畫面也就不會刷新。反饋到用戶身上,就是用戶盯着同一張圖看了 32ms 而不是 16ms ,也就是說掉幀發生了。框架
掉幀是用戶體驗中一個很是核心的問題。丟棄了當前幀,而且以後不可以延續以前的幀率,這種不連續的間隔會容易會引發用戶的注意,也就是咱們常說的卡頓、不流暢。函數
引發掉幀的緣由很是多,好比:工具
花了很是多時間從新繪製界面中的大部分東西,這樣很是浪費CPU週期;佈局
過分繪製嚴重,在繪製用戶看不到的對象上花費了太多的時間;性能
有一大堆動畫重複了一遍又一遍,消耗 CPU 、 GPU 資源;學習
頻繁的觸發垃圾回收;測試
Android系統要求每一幀都要在 16ms 內繪製完成,那麼1秒的幀率就是約 60 幀每秒( 1秒 / 0.016幀每秒 = 62.5幀/秒 ),那爲何要以 60 Fps來做爲 App 性能的衡量標準呢?這是由於人眼和大腦之間的協做沒法感知到超過 60 Fps的畫面更新。
市面上絕大多數Android設備的屏幕刷新頻率是 60 HZ。固然,超過 60 Fps 是沒有意義的,人眼感知不到區別。24 Fps 是人眼能感知的連續線性的運動,因此是電影膠圈的經常使用幀率,由於這個幀率已經足夠支撐大部分電影畫面所要表達的內容,同時能最大限度地減小費用支出。可是,低於 30 Fps 是沒法順暢表現絢麗的畫面內容的,此時就須要用到 60 Fps 來達到想要表達的效果。
應用的界面性能目標就是保持 60 Fps,這意味着每一幀你只有 16 ms(1秒 / 60幀率)的時間來處理全部的任務。
垃圾回收器是一個在應用運行期間自動釋放那些再也不引用的內存的機制,常稱 GC 。頻繁的 GC 也是致使嚴重性能問題的罪魁禍首之一。
前面提到,平滑的完成一幀意味着全部渲染代碼都必須在 16ms 內完成。頻繁的 GC 會嚴重限制一幀時間內的剩餘時間,若是 GC 所作的工做超過了那些必須的工做,那麼留給應用平滑的幀率的時間就越少。越接近 16ms ,在垃圾回收事件觸發的時候,就越容易致使卡頓。
注意,Android4.4 引進了新的 ART 虛擬機來取代 Dalvik 虛擬機。它們的機制大有不一樣,簡單而言:
ART 虛擬機相對於 Dalvik 虛擬機來講的垃圾回收來講有一個很大的性能提高,但 2 - 3 ms 的回收時間對於超過16ms幀率的界限也是足夠的。所以,儘管垃圾回收在 Android 5.0 以後再也不是耗資源的行爲,但也是始終須要儘量避免的,特別是在執行動畫的狀況下,可能會致使一些讓用戶明顯感受的丟幀。
若是對軟件測試、接口測試、自動化測試、性能測試、LR腳本開發、面試經驗交流。感興趣能夠175317069,羣內會有不按期的發放免費的資料連接,這些資料都是從各個技術網站蒐集、整理出來的,若是你有好的學習資料能夠私聊發我,我會註明出處以後分享給你們。
UI 線程是應用的主線程,不少的性能和卡頓問題是因爲咱們在主線程中作了大量的工做。
因此,全部耗資源的操做,好比 IO 操做、網絡操做、SQL 操做、列表刷新等,都應該用後臺進程去實現,不能佔用主線程,主線程是 UI 線程,是保持程序流暢的關鍵;
在 Android 5.0 版本里,Android 框架層引入了 「 Render Thread 」 ,用於向 GPU 發送實際渲染的操做。這個線程減輕了一些 UI 線程減小的操做。可是輸入、滾動和動畫仍然在 UI thread,由於 Thread 必須可以響應操做。
垂直同步是 Android4.1 經過 Project Butter 在 UI 架構中引入的新技術,同期引入的還有 Triple Buffer 和 HWComposer 等技術,都是爲提升 UI 的流暢性而生。
舉個例子,你拍了一張照片,而後旋轉5度再拍另一張照片,將兩照片的中間剪開並拼接在一塊兒,獲得下圖:中間這部分有明顯區別的部分,等價於設備刷新率和幀速率不一致的結果。
通常而言, GPU 的幀速率應高於刷新率,纔不會卡頓或掉幀。若是屏幕刷新率比幀速率還快,屏幕會在兩幀中顯示同一個畫面,這種斷斷續續狀況持續發生時,用戶將會很明顯地感受到動畫的卡頓或者掉幀,而後又恢復正常,咱們常稱之爲閃屏、跳幀、延遲。
應用應避免這些幀率降低的狀況,以確保 GPU 能在屏幕刷新以前完成數據的獲取及寫入,保證動畫流暢。
絕大多數渲染操做都依賴兩個硬件: CPU 、 GPU 。 CPU 負責 Measure 、 layout 、 Record 、 Execute 的計算操做, GPU 負責柵格化( Rasterization )操做。 非必需的視圖組件會帶來多餘的 CPU 計算操做,還會佔用多餘的 GPU 資源。
若是對軟件測試、接口測試、自動化測試、性能測試、LR腳本開發、面試經驗交流。感興趣能夠175317069,羣內會有不按期的發放免費的資料連接,這些資料都是從各個技術網站蒐集、整理出來的,若是你有好的學習資料能夠私聊發我,我會註明出處以後分享給你們。
柵格化( Rasterization )能將 Button 、 Shape 、 Path 、 Bitmap 等資源組件拆分到不一樣的像素上進行顯示。這個操做很費時,因此引入了 GPU 來加快柵格化的操做。
CPU 負責把 UI 組件計算成多邊形( Polygons ),紋理( Texture ),而後交給 GPU 進行柵格化渲染,再將處理結果傳到屏幕上顯示。
在 Android 裏的那些資源組件的顯示(好比 Bitmaps 、 Drawable ),都是一塊兒打包到統一的紋理( Texture )當中,而後再傳遞到 GPU 裏面。
圖片的顯示,則是先通過 CPU 的計算加載到內存中,再傳給 GPU 進行渲染。
文字的顯示,則是先通過 CPU 換算成紋理( Texture ),再傳給 GPU 進行渲染,返回到 CPU 繪製單個字符的時候,再從新引用通過 GPU 渲染的內容。
動畫的顯示更加複雜,咱們須要在 16 ms 內處理完全部 CPU 和 GPU 的計算、繪製、渲染等操做,才能得到應用的流暢體驗。
根據業務的不一樣與所須要的測試粒度的不一樣,就會有不一樣的檢測維度。目前我所在業務所需的界面性能檢測維度以下:
還有專項測試中某些用戶場景可能還包含着另一些隱形的檢測維度,好比:
檢測和解決界面性能問題很大程度上依賴於你的應用程序架構,幸運的是,Andorid 提供了不少調試工具,知道並學會使用這些工具很重要,它們能夠幫助咱們調試和分析界面性能問題,以讓應用擁有更好的性能體驗。下面列舉Android常見的界面性能調試工具:
2.2.1 Hierarchy View
若是對軟件測試、接口測試、自動化測試、性能測試、LR腳本開發、面試經驗交流。感興趣能夠175317069,羣內會有不按期的發放免費的資料連接,這些資料都是從各個技術網站蒐集、整理出來的,若是你有好的學習資料能夠私聊發我,我會註明出處以後分享給你們。
2.2.2 Lint
Lint 是 ADT 自帶的靜態代碼掃描工具,能夠給 XML 佈局文件和 項目代碼中不合理的或存在風險的模塊提出改善性建議。官方關於 Lint 的實際使用的提示,列舉幾點以下:
merge
標籤;
2.2.3 Systrace
Systrace 在Android DDMS 裏自帶,能夠用來跟蹤 graphics 、view 和 window 的信息,發現一些深層次的問題。很麻煩,限制大,實際調試中我基本用不到。
2.2.4 Track
Track 在 Android DDMS裏自帶,是個很棒的用來跟蹤構造視圖的時候哪些方法費時,精確到每個函數,不管是應用函數仍是系統函數,咱們能夠很容易地看到掉幀的地方以及那一幀全部函數的調用狀況,找出問題點進行優化。
2.2.5 OverDraw
經過在 Android 設備的設置 APP 的開發者選項裏打開 「 調試 GPU 過分繪製 」 ,來查看應用全部界面及分支界面下的過分繪製狀況,方便進行優化。
2.2.6 GPU 呈現模式分析
經過在 Android 設備的設置 APP 的開發者選項裏啓動 「 GPU 呈現模式分析 」 ,能夠獲得最近 128 幀 每一幀渲染的時間,分析性能渲染的性能及性能瓶頸。
2.2.7 StrictMode
經過在 Android 設備的設置 APP 的開發者選項裏啓動 「 嚴格模式 」 ,來查看應用哪些操做在主線程上執行時間過長。當一些操做違背了嚴格模式時屏幕的四周邊界會閃爍紅色,同時輸出 StrictMode 的相關信息到 LOGCAT 日誌中。
2.2.8 Animator duration scale
經過在 Android 設備的設置 APP 的開發者選項裏打開 「 窗口動畫縮放 」 / 「 過渡動畫縮放 」 / 「 動畫程序時長縮放 」,來加速或減慢動畫的時間,以查看加速或減慢狀態下的動畫是否會有問題。
2.2.9 Show hardware layer updates
經過在 Android 設備的設置 APP 的開發者選項裏啓動 「 顯示硬件層更新 」,當 Flash 硬件層在進行更新時會顯示爲綠色。使用這個工具可讓你查看在動畫期間哪些不指望更新的佈局有更新,方便你進行優化,以得到應用更好的性能。實例《 Optimizing Android Hardware Layers 》。
前面提到過我司的目前所需的測試維度以下:
故接下來將圍繞這三兩點,分別從概念、追蹤、挖掘根源以及排查的工具來具體講述如何解決,以及給開發的優化建議。
過分繪製是一個術語,表示某些組件在屏幕上的一個像素點的繪製次數超過 1 次。
通俗來說,繪製界面能夠類比成一個塗鴉客塗鴉牆壁,塗鴉是一件工做量很大的事情,牆面的每一個點在塗鴉過程當中可能被塗了各類各樣的顏色,但最終呈現的顏色卻只多是 1 種。這意味着咱們花大力氣塗鴉過程當中那些非最終呈現的顏色對路人是不可見的,是一種對時間、精力和資源的浪費,存在很大的改善空間。繪製界面同理,花了太多的時間去繪製那些堆疊在下面的、用戶看不到的東西,這樣是在浪費CPU週期和渲染時間!
官方例子,被用戶激活的卡片在最上面,而那些沒有激活的卡片在下面,在繪製用戶看不到的對象上花費了太多的時間。
經過在 Android 設備的設置 APP 的開發者選項裏打開 「 調試 GPU 過分繪製 」 ,來查看應用全部界面及分支界面下的過分繪製狀況,方便進行優化。
Android 會在屏幕上顯示不一樣深淺的顏色來表示過分繪製:
設備的硬件性能是有限的,當過分繪製致使應用須要消耗更多資源(超過了可用資源)的時候性能就會下降,表現爲卡頓、不流暢、ANR 等。爲了最大限度地提升應用的性能和體驗,就須要儘量地減小過分繪製,即更多的藍色色塊而不是紅色色塊。
實際測試,經常使用如下兩點來做爲過分繪製的測試指標,將過分繪製控制在一個約定好的合理範圍內:
過分繪製很大程度上來自於視圖相互重疊的問題,其次還有沒必要要的背景重疊。
官方例子,好比一個應用全部的View都有背景的話,就會看起來像第一張圖中那樣,而在去除這些沒必要要的背景以後(指的是Window的默認背景、Layout的背景、文字以及圖片的可能存在的背景),效果就像第二張圖那樣,基本沒有過分繪製的狀況。
當佈局文件的節點樹的深度越深,XML 中的標籤和屬性設置越多,對界面的顯示有災難性影響。
一個界面要顯示出來,第一步會進行解析佈局,在 requestLayout 以後還要進行一系列的 measure 、 layout 、 draw 操做,若佈局文件嵌套過深、擁有的標籤屬性過於臃腫,每一步的執行時間都會受到影響,而界面的顯示是進行完這些操做後纔會顯示的,因此每一步操做的時間增加,最終顯示的時間就會越長。
有能力且有興趣看源碼的童鞋,過分繪製的源碼位置在: /frameworks/base/libs/hwui/OpenGLRenderer.cpp ,有興趣的能夠去研究查看。
C-like
if (Properties::debugOverdraw && getTargetFbo() == 0) { const Rect* clip = &mTilingClip; mRenderState.scissor().setEnabled(true); mRenderState.scissor().set(clip->left, mState.firstSnapshot()->getViewportHeight() - clip->bottom, clip->right - clip->left, clip->bottom - clip->top); // 1x overdraw mRenderState.stencil().enableDebugTest(2); drawColor(mCaches.getOverdrawColor(1), SkXfermode::kdata-urlOver_Mode); // 2x overdraw mRenderState.stencil().enableDebugTest(3); drawColor(mCaches.getOverdrawColor(2), SkXfermode::kdata-urlOver_Mode); // 3x overdraw mRenderState.stencil().enableDebugTest(4); drawColor(mCaches.getOverdrawColor(3), SkXfermode::kdata-urlOver_Mode); // 4x overdraw and higher mRenderState.stencil().enableDebugTest(4, true); drawColor(mCaches.getOverdrawColor(4), SkXfermode::kdata-urlOver_Mode); mRenderState.stencil().disable(); } }
渲染性能每每是掉幀的罪魁禍首,這種問題很常見,讓人頭疼。好在 Android 給咱們提供了一個強大的工具,幫助咱們很是容易追蹤性能渲染問題,看到到底是什麼致使你的應用出現卡頓、掉幀。
經過在 Android 設備的設置 APP 的開發者選項裏打開 「 GPU 呈現模式分析 」 選項,選擇 」 在屏幕上顯示爲條形圖 「 。
這個工具會在Android 設備的屏幕上實時顯示當前界面的最近 128 幀 的 GPU 繪製圖形數據,包括 StatusBar 、 NavBar 、 當前界面的 GPU 繪製圖形柱狀圖數據。咱們通常只需關心當前界面的 GPU 繪製圖形數據便可。
界面上一共有 128 個小柱狀圖,表明的是當前界面最近的 128 幀 GPU 繪製圖形數據。一個小柱狀圖表明的這一幀畫面渲染的耗時,柱狀圖越高表明耗時越長。隨着界面的刷新,柱狀圖信息也會實時滾動刷新。
中間有一條綠線,表明 16 ms ,保持動畫流暢的關鍵就在於讓這些垂直的柱狀條儘量地保持在綠線下面,任什麼時候候超過綠線,你就有可能丟失一幀的內容。
每個柱狀圖都是由三種顏色構成:藍、紅、黃。
藍色表明的是這一幀繪製 Display List 的時間。通俗來講,就是記錄了須要花費多長時間在屏幕上更新視圖。用代碼語言來講,就是執行視圖的 onDraw 方法,建立或更新每個視圖的 Display List 的時間。
紅色表明的是這一幀 OpenGL 渲染 Display List 所須要的時間。通俗來講,就是記錄了執行視圖繪製的耗時。用代碼語言來講,就是 Android 用 OpenGL ES 的 API 接口進行 2D 渲染 Display List 的時間。
黃色表明的是這一幀 CPU 等待 GPU 處理的時間。通俗來講,就是 CPU 等待 GPU 發出接到命令的回覆的等待時間。用代碼語言來講,就是這是一個阻塞調用。
實際測試,經常使用如下兩點來做爲渲染性能的測試指標,將渲染性能控制在一個約定好的合理範圍內:
當你看到藍色的線較高的時候,多是因爲你的視圖忽然無效了須要從新繪製,或者是自定義的視圖過於複雜耗時過長。
當你看到紅色的線較高的時候,多是因爲你的視圖從新提交了須要從新繪製致使的(好比屏幕從豎屏旋轉成橫屏後當前界面從新建立),或者是自定義的視圖很複雜,繪製起來很麻煩,致使耗時過長。好比下面這種視圖:
若是對軟件測試、接口測試、自動化測試、性能測試、LR腳本開發、面試經驗交流。感興趣能夠175317069,羣內會有不按期的發放免費的資料連接,這些資料都是從各個技術網站蒐集、整理出來的,若是你有好的學習資料能夠私聊發我,我會註明出處以後分享給你們。
當你看到黃色的線較高的時候,那就意味着你給 GPU 太多的工做,太多的負責視圖須要 OpenGL 命令去繪製和處理,致使 CPU 遲遲沒等到 GPU 發出接到命令的回覆。
這個工具可以很好地幫助你找到渲染相關的問題,幫助你找到卡頓的性能瓶頸,追蹤到底是什麼致使被測應用出現卡頓、變慢的狀況,以便在代碼層面進行優化。甚至讓負責產品設計的人去改善他的設計,以得到良好的用戶體驗。
檢測渲染性能時,常伴隨着開啓「 嚴格模式 」 查看應用哪些情景在 UI 線程(主線程)上執行時間過長。
另外有些強大但可能少用的工具在測試性能渲染時輔助分析,好比:
如上面所說,佈局和 UI 組件等都會先通過 CPU 計算成 GPU 可以識別並繪製的多邊形( Polygons ),紋理( Texture ),而後交給 GPU 進行柵格化渲染,再將處理結果傳到屏幕上顯示。 「 CPU 計算成 GPU 可以識別並繪製的對象 」 這個操做是在 DisplayList 的幫助下完成的。DisplayList 擁有要交給 GPU 柵格化渲染到屏幕上的數據信息。
DisplayList 會在某個視圖第一次須要渲染時建立。當該視圖有相似位置被移動等變化而須要從新渲染這個視圖的時候,則只需 GPU 額外執行一次渲染指令冰更新到屏幕上就夠了。但若是視圖中的繪製內容發生變化時(好比不可見了),那之間的 DisplayList 就沒法繼續使用了,這時系統就會從新執行一次從新建立 DisplayList 、渲染DisplayList 並更新到屏幕上。這個流程的表現性能取決於該視圖的複雜程度。
這一章節比較簡單,考慮到應該沒受衆,故不展開討論。
佈局結構太複雜,會減慢渲染的速度,形成性能瓶頸。咱們能夠經過如下這些慣用、有效的佈局原則來優化:
RelativeLayout
。相對佈局 RelativeLayout
比較耗資源,由於一個相對佈局 RelativeLayout
須要兩次度量來確保本身處理了全部的佈局關係,並且這個問題會伴隨着視圖層級中的相對佈局 RelativeLayout
的增多,而變得更嚴重;LinearLayout
代替相對佈局 RelativeLayout
,由於線性佈局 LinearLayout
性能要更高一些;確實須要對分支進行相對佈局 RelativeLayout
的時候,能夠考慮更優化的網格佈局 GridLayout
,它已經預處理了分支視圖的關係,能夠避免兩次度量的問題;RelativeLayout
,相對佈局 RelativeLayout
能夠簡單實現線性佈局 LinearLayout
嵌套才能實現的佈局;AbsoluteLayout
;</include>
標籤進行重用。若是應用多個地方的 UI 用到某個佈局,就將其寫成一個佈局部件,便於各個 UI 重用。merge
標籤減小布局的嵌套層次LinearLayout
每個子組件都須要被測量兩次,會消耗過多的系統資源。在使用 ListView
標籤與 GridView
標籤的時候,這個問題顯的尤爲重要,由於子組件會重複被建立。平分佈局可使用相對佈局 RelativeLayout
裏一個 0dp 的 view 作分割線來搞定,若是不行,那就……;ViewStub
標籤來加載一些不經常使用的佈局;ViewStub
標籤的 setVisiblity 性能要好,固然某些功能的實現採用 ViewStub
標籤更合適;Application
層級初始化代碼。出處:https://blog.csdn.net/Stephen_shijun/article/details/84103669