Android效能優化(4):UI渲染機制以及優化

無名之輩FTER發表於2020-02-16

從Android 6.0原始碼的角度剖析View的繪製原理一文中,我們瞭解到View的繪製流程有三個步驟,即measure(測量)、layout(佈局)和draw(繪製),它們主要執行在系統應用框架層,而真正將資料渲染到螢幕上的則是系統Native層的SurfaceFlinger服務來完成的。本文將暫不對SurfaceFlinger服務的執行流程進行剖析,而是從更加底層的角度來了解APP的渲染機制,同時引出在渲染過程中遇到的效能問題,以及如何去發現、優化它們。

1. 渲染機制分析

1.1 渲染機制

 對於開發者來說,APP的介面主要是由XML佈局檔案來表現的,每個XML佈局檔案中又包括了很多檢視元件,比如ImageView、Button、TextView等等,它們分別表示了圖片、按鈕、字串等不同的資訊,那麼這些複雜的XML佈局檔案和標記語言,又是如何轉化成為使用者能夠看得懂的影象的呢?答案是:格柵化(Rasterization)!所謂格柵化,就是將例如字串按鈕路徑或者形狀等的一些高階物件,拆分到不同的畫素螢幕上進行顯示。格柵化是一個非常費時的操作,CPU作為中央處理器本身任務就比較繁重,因此人們引入了GPU(影象處理器)這塊特殊的硬體來加快格柵化操作(硬體加速)。格柵化操作大體如下:
在這裡插入圖片描述
 接下來,我們就來詳細瞭解XML佈局檔案中的UI元件是如何被格柵化並渲染顯示在螢幕上的?在APP繪製渲染過程中,與繪製渲染有關的硬體主要有CPUGPU(圖形處理器),其中,CPU負責把UI元件計算成Polygons(多邊形)Texture(紋理),而CPU負責格柵化和渲染工作。CPU和GPU通過圖形驅動層進行連線,這個圖形驅動層維護了一個Display List佇列,它們分別充當生產者消費者,協作完成具體的繪製渲染過程。繪製渲染過程如下圖所示:
在這裡插入圖片描述

  • 渲染流程如下:

首先CPU會對UI元件(View)進行MeasureLayoutRecordExecute的資料計算工作,以將其計算成的Polygons(多邊形)Texture(紋理),它們是GPU能夠識別的物件,而承載這些資訊的是一個被稱為Display List的結構體,它持有所有交給GPU繪製到螢幕上的資料資訊,包含GPU要繪製的全部物件的資訊列表和執行繪製操作的OpenGL命令列表。在某個View第一次需要被渲染的時候,Display List會因此被建立,當這個View需要顯示到螢幕上時,GPU接收到繪製指令後會執行該Display List。每個View擁有自己的Display ListDisplay Lis本身也構成一個樹狀的結構,跟View Hierachy(檢視樹)保持一致。
在這裡插入圖片描述
其次,由於每次從CPU計算得到的PolygonsTexture提交(轉移)GPU是一件比較麻煩且耗時的事情(注:實際提交的是Display List),因此Android系統又引入了OpenGL ES,該庫API允許將那些需要渲染的PolygonsTexture儲存(Hold)在GPU儲存器(視訊記憶體)中,當下一次需要渲染的時候只需要在GPU儲存器裡引用它,然後告訴OpenGL如何繪製就可以了,而不再需要經過CPU上傳。需要注意的是,假如View的繪製內容發生變化,那麼GPU Memory儲存的Display List就無法再繼續使用,這時就需要CPU重新計算建立Display List並重新執行指令更新到螢幕。
在這裡插入圖片描述
 最後,當GPU完成對紋理的格柵化、渲染後,它會將渲染的結果放入幀緩衝區,視訊控制器會按照VSync(垂直同步)訊號逐行讀取幀緩衝區的資料,經過可能的數模轉換傳遞給顯示器顯示。

  • CPU、OpenGL與GPU之間的關係
    在這裡插入圖片描述

1.2 卡頓現象

 前面說到,當GPU渲染完成後會將渲染的結果儲存到幀緩衝區,視訊控制器會按照VSync(垂直同步)訊號逐行讀取幀緩衝區的資料,經過可能的數模轉換傳遞給顯示器顯示。那麼問題來了,什麼是VSYNC訊號?在講解VSYNC之前,我們需要了解兩個相關的概念:Refresh RateFrame Rate

  • Refresh Rate(重新整理頻率)

 表示螢幕在一秒內被重新整理的次數,取決於硬體的固定引數,目前大部分手機這個固定引數(螢幕重新整理頻率)為60Hz。也就是說,Android系統每隔約16ms(1000ms/60=16.66ms)就會重新重新整理一次介面(Activity),因此我們有16ms的時間去完成每幀的繪製、渲染的邏輯操作。
在這裡插入圖片描述

  • Frame Rate(幀率)

 表示GPU在一秒內能夠渲染的幀數,通常為60fps。為什麼是60fps?這是因為人眼與大腦之間的協作無法感知超過60fps的畫面更新。簡單的說,人眼看到的動畫其實都是一幀幀連續播放的靜態圖片,當播放的速度達到1秒針24幀(24fps)時,對於人眼感知來說就是連續的線性運動。當然低於30fps在某些場景仍然無法順暢表現絢麗的畫面,此時就需要60fps來達到想要的效果。

 現在我們再來理解下VSYNC訊號:**螢幕的重新整理過程是每一行從左到右(水平重新整理,Horizontal Scanning),從上到下(垂直重新整理,Verical Scanning)。當整個螢幕重新整理完畢,即一個垂直重新整理週期完成,會有短暫的空白期,此時Android系統就會發出VSYNC訊號,觸發下一幀對UI的渲染、顯示。VSYNC是一種定時中斷,一旦收到VSYNC訊號CPU就開始處理幀資料,通常Android系統每隔16ms發出VSYNC訊號,這個週期時間由螢幕重新整理頻率決定。**通常來說,幀率超過重新整理頻率只是一種理想的狀態,在超過60fps的情況下,GPU所產生的幀資料會因為等待VSYNC的重新整理資訊而被Hold住,這樣能夠保持每次螢幕重新整理都有實際的新的資料可以顯示。但是基本上我們遇到的是幀率<=螢幕重新整理頻率的情況,尤其是在幀率小於重新整理頻率時,會出現待VSYNC訊號到來時,螢幕沒有可以重新整理的資料,即幀緩衝區還是之前的那幀影象,這就會導致螢幕顯示的該幀畫面內容仍然是上一幀的畫面,而這種現象我們就稱之為"掉幀",對於使用者來說,就是介面出現了卡頓現象,即執行不流暢。
在這裡插入圖片描述
 由此我們可以得出,Android系統之所以會出現卡頓現象是因為的某些操作耗費了幀間隔時間(16ms),導致其他類似計算、渲染等操作的可用時間就會變少,在16ms無法完成正常的繪製、渲染工作。當下一個VSYNC訊號到來時,Android系統嘗試在螢幕上繪製新的一幀,但是新的一幀還沒準備好,就會導致無法進行正常渲染,畫面就不會重新整理,使用者看到的還是上一幀的畫面,從而發生了丟幀。產生卡頓的原因有很多,主要有以下幾點:

  • 佈局Layout過於複雜,無法在16ms內完成渲染;
  • 同一時間動畫執行的次數過多,導致CPU或GPU負載過重;
  • View過度繪製,導致某些畫素在同一幀時間內被繪製多次
  • 在UI執行緒中做了很多耗時的操作;
  • GC回收時暫停時間過長或者頻繁GC產生大量的暫停時間(記憶體抖動);

1.3 記憶體抖動

 在1.2小節我們談到,大量不停的GC操作會顯著佔用幀間隔時間(16ms),如果在幀間隔時間裡面做了過多的GC操作,那麼自然其他類似計算,渲染等操作的可用時間就變得少了,就容易出現丟幀現象,而導致這種頻繁GC的原因之一就是“記憶體抖動(Memory Churn)”。記憶體抖動是因為大量的物件被建立又在短時間內馬上被釋放,瞬間產生大量的物件會嚴重佔用年輕代(Yong Generation)的記憶體區域,當達到閥值時剩餘空間不夠的時候,也會觸發GC。即使每次分配的物件佔用了很少的記憶體,但是他們疊加在一起會增加Heap的壓力,從而觸發更多其他型別的GC。
在這裡插入圖片描述

2. 渲染優化方式

 從上一小節的分析可知,Android系統的渲染機制主要體現在CPU的繪製和GPU的格柵化、渲染兩個階段,其中,主要比較耗時的在CPU的繪製過程,即將UI物件轉換為一系列的多邊形和紋理,和從CPU上傳Display List資料到GPU過程。如果CPU/GPU 負載過量或者上傳資料次數過多,就會導致 16ms 內沒有繪製、渲染完成出現渲染效能問題。因此,對於渲染效能方面的的優化,我們將從這兩個方面進行剖析,即減輕CPU/GPU的負載量和減少佔用額外的GPU資源。下面我們就介紹幾個工具來幫助我們發現、解決一些渲染效能優化問題,主要有Profile GPU RenderingSysTrace以及TraceView等。

2.1 過度繪製優化

 所謂過度繪製,指的是在螢幕上某個畫素在同一幀時間內被繪製多次,從而浪費了CPU和GPU的資源。舉個例子來說,假如我們要粉刷房子的牆壁,一開始刷綠色,接著又開始刷黃色,這樣黃色就將綠色蓋住了,為此第一次的粉刷就白乾了。產生過度繪製主要有兩個原因:

  • 在XML佈局中,控制元件有重疊且都有設定背景
  • View的onDraw在同一區域繪製多次;

2.1.1 Show GPU overdraw

Show GPU overdraw是Android系統提供的一個檢視介面過度繪製的工具,我們可以在手機設定裡的開發者選項中開啟它,即開發者選項->除錯GPU過度繪製。Show GPU overdraw效果:
在這裡插入圖片描述
 開啟除錯GPU過度繪製後,我們的介面就會出現各種顏色,它們的具體含義如下:

  • 白色:沒有過度繪製,即每個畫素點在螢幕上只繪製了一次;
  • 藍色:一次過度繪製,即每個畫素點在螢幕上繪製了兩次;
  • 綠色:二次過度繪製,即每個畫素點在螢幕上繪製了三次;
  • 粉紅色:三次過度繪製,即每個畫素點在螢幕上繪製了四次;
  • 紅色:四次以上過度繪製;

 為此我們可以得出,一個合格的介面應該以白色和藍色為主,綠色以上的區域不要超過整體的三分之一,總之顏色越淺越好。

2.1.2 Profile GPU Rendering

 Profile GPU Rendering是Android4.1系統引入用於展示GPU渲染每幀時各個階段所消耗的時間,以便於我們可以直接觀察到渲染該幀時各個階段的耗時情況,即有沒有超過16ms。我們可以在手機設定裡開發者選項中開啟它(開發者選項->GPU顯示配置檔案/GPU呈現模式分析->在螢幕上顯示為條形圖),接著手機螢幕的底部就會出現彩色的柱狀。效果如下圖所示:
在這裡插入圖片描述
 圖中綠色橫軸代表幀時間,彩色的柱狀(縱軸)表示某一幀的耗時。綠色的橫線為警戒線,超過這條線則意味著該幀繪製渲染的時間超過了16ms,我們應儘量保證垂直的彩色柱狀圖保持在綠線下面,任何時候一幀超過綠線,我們的app將會丟掉一幀。每一個彩色柱狀圖代表一幀的渲染,越長的垂直柱狀圖表示這一幀需要渲染的時間越長。當APP在執行時,我們會看到手機底部的柱狀圖會從左到右動態地顯示,隨著需要渲染的幀數越來越多,他們回堆積在一起,這樣就可以觀察到這段時間幀率的變化。下圖為柱狀圖中不同顏色代表的意義:
在這裡插入圖片描述
顏色意義解釋

  • 橘色:代表處理的時間。代表CPU在等待GPU完成工作的時間,如果過高表示GPU很繁忙;

  • 紅色:代表執行的時間。Android 的2D渲染器向OpenGL發出命令繪製或重繪display lists 花費的時間,柱子的高度等於所有Display list繪製時間的總和。如果紅色柱狀圖很高,可能由於重新提交檢視而導致,還有複雜的自定義View也會導致紅的柱狀圖變高;

  • 淺藍色:向CPU傳輸Bitmap花費的時間,過高代表了載入了大量圖形;

  • 深藍色:代表繪製的時間。也就是需要多長時間去建立和更新Dispaly List。過高代表在onDraw中花費過多時間,可能是自定義畫圖操作太多或執行了其它操作;

  • 淡綠色:代表了onLayoutonMeasure方法消耗的總時間,這段很高代表遍歷整個view樹結構花費了太多時間;

  • 綠色:代表為該幀內所有animator求值(屬性動畫中代表通過估值器計算屬性的具體值)所花費的時間.如果這部分過高,代表自定義animator效能不佳或者更新view屬性引發了某些意外操作;

  • 深綠色:代表app在使用者輸入事件回撥中花費的時間,這部分過高可能意味著app處理使用者輸入事件時間過長,建議將操作分流到工作執行緒;

  • 墨綠色:代表在連續兩幀間的時間間隔,可能是因為子執行緒執行時間過長搶佔了UI執行緒被cpu執行的機會。

 為此,我們可以得出在Profile GPU Rendering中,假如紅色/橘色佔比較大,說明可能出現重複佈局的情況,可以從否減少檢視層級、減少無用的背景圖、減輕自定義控制元件複雜度等方面去優化;假如藍色/淺藍/各種綠色佔比較大,應該從耗時操作這方面去優化。當然,Profile GPU Rendering可以找到渲染有問題的介面,但是想要修復的話,只依賴Profile GPU Rendering是不夠的,我們可以通過如下兩款工具來定位問題,即TraceViewHierarchy Viewer,前者能夠詳細分析問題原因;後者能夠檢視佈局的層次和每個View所花費的時間。Systrace

總之,我們應儘量從以下幾個方面避免過度繪製。

  • 移除無用的背景圖;
  • 減少檢視層級,儘量使用扁平化佈局,比如Relativeayout;
  • 減輕自定義控制元件複雜度,重疊區域可以使用canvas.clipRect方法指定繪製區域;`

2.2 卡頓優化

 前面我們談到,Android系統之所以會出現卡頓現象是因為的某些操作耗費了幀間隔時間(16ms),導致其他類似計算、渲染等操作的可用時間就會變少,在16ms無法完成正常的繪製、渲染工作。當下一個VSYNC訊號到來時,Android系統嘗試在螢幕上繪製新的一幀,但是新的一幀還沒準備好,就會導致無法進行正常渲染,畫面就不會重新整理,使用者看到的還是上一幀的畫面,從而發生了丟幀,這就是"卡頓現象"。下面我們介紹兩款分析介面卡頓的利器,即SysTraceTraceView,其中,SysTrace為卡頓原因指明大體方向,TraceView則是找到是什麼讓CPU繁忙、某些方法的呼叫次數等具體資訊。

2.2.1 SysTrace

SysTrace是Android 4.1中新增的效能資料取樣和分析工具,它可以幫助我們收集Android關鍵子系統的執行資訊,如SurfaceFlinger、WMS等Framework部分關鍵模組、服務、View體系系統等。Systrace的功能包括跟蹤系統的I/O操作、核心工作佇列、CPU負載以及Android各個子系統的執行狀態。**對於UI顯示效能,比如動畫播放不流暢、渲染卡頓等問題提供了分析資料。**我們可以在AS的Android Device Monitor(DDMS)開啟Systrace,需要注意的是,AS 3.0以後谷歌已將DDMS從AS皮膚上移除,但我們仍然可以開啟sdk目錄/tools/monitor.bat使用它。SysTrace使用方法如下:
在這裡插入圖片描述

  • 具體步驟:
  1. 雙擊sdk目錄/tools/monitor.bat開啟DDMS,單擊DDMS皮膚上的Systrace按鈕;

  2. 進入抓取設定介面後設定跟蹤的時長,以及trace.html檔案輸出路徑等內容;

  3. 操作APP我們懷疑卡頓的地方,對該過程進行跟蹤;

  4. 待跟蹤結束後就會在指定路徑生產trace.html檔案,接下來用Chrome瀏覽器開啟它進行分析。

  • 用Chrome分析trace.html
    在這裡插入圖片描述
     總體來說,trace.html主要記錄了Android系統中所有程式和執行緒執行資訊,且同一個程式內按執行緒進行縱向拆分,每個執行緒均記錄了自己的工作。從上圖可知,在trace.html檔案中我們應著重關注三個方面:AlertsFramesKernel CPU,下面我們就詳細分析如何使用它們來定位問題。
  1. Alerts部分

 Alerts部分是Systrace自動分析trace中的事件,並能自動高亮某個效能問題作為一個Alerts(警告),建議除錯人員下一步怎麼做。可以通過點選頂部淺藍色圓圈檢視某一個警告,或者點選右側的Alerts選項列出所有警告資訊,這些資訊將會按類別列出,比如上圖中列出了Scheduling delay。選中一條Alert詳情如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-g2UlHVKr-1574213695824)(F:\360MoveData\Users\Jiangdg\Desktop\效能優化\插圖\APK6.png)]

Scheduling delay(排程延遲)的意思就是一個執行緒在處理一塊運算的時候,在很長一段時間都沒有被分配到CPU上面做運算,從而導致這個執行緒在很長一段時間都沒有完成工作。從上圖可以看出,選中的這幀只執行了2.343ms,而有101.459ms是在休眠,這就意味著這一幀的渲染過程非常慢。當然僅僅通過Alerts的提示仍然無法找到渲染慢的原因,接下來就需要藉助Frames部分進一步定位。

  1. Frames部分

 Frames部分給出的是應該的幀數,每一幀就是一個F圓圈F圓圈有三種顏色:綠色、黃色和紅色,其中,綠色表示該幀渲染流暢(即沒有超過16.66ms,滿足每秒60幀穩定所需的幀),黃色和紅色表示該幀的渲染時間超過了16.66ms,這就意味著黃色和紅色代表的幀存在渲染效能問題(紅色比黃色更嚴重)。我們點選紅色的F圓圈,在皮膚的底部會給出具體的Alert資訊(同Alert部分),然後我們再按下電腦鍵盤上的M鍵可以看到被高亮的部分就是這幀精確的時間耗時。應用區域的Frames展示如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-yIq8gjzg-1574213695824)(F:\360MoveData\Users\Jiangdg\Desktop\效能優化\插圖\APK7.png)]

 由於Android 5.0以上系統UI渲染的工作是在UI ThreadRenderThread完成的,我們使用鍵盤的W鍵對這兩個區域放大,然後選擇兩個執行緒中最長的一塊區域(表示某個函式方法)觀察那些View在被填充過程中耗時比較嚴重。我們點選DrawFrame這個方法,在皮膚的底部可以得到以下資訊:
在這裡插入圖片描述
 從上圖可以看出,Wall Duration代表著這一塊區域的開始到結束的耗時,為204.877ms;CPU Duration代表實際CPU在處理這一塊區域的耗時,即分配CPU的時長0.899ms。很顯然,這兩個時間差距非常大,CPU只消耗了不到1ms的時間來運算這塊區域。這就意味著可能其他執行緒/程式長期佔用CPU,導致RenderThread無法進行正常運算出現渲染異常。接下來,我們就通過分析Kernel CPU部分進一步確定是哪個執行緒/程式長期佔用CPU。

  1. Kernel CPU部分

 在Kernel CPU區域,每一行代表一個CPU核心和它執行任務的時間片,放大後會看到每個色塊代表一個執行的程式,色塊的長度代表其執行時間。如下圖所示:
在這裡插入圖片描述
 在之前選中的幀區域,我們很容易看到一個很長的綠色塊,位於CPU2上,這個綠色塊CPU執行的程式為HeapTaskDaemon,從程式名來看很容易猜出這個程式就是我們的GC守護程式。這就意味著,在這一幀內執行了長時間的垃圾回收操作,由於系統執行GC操作時會將正在執行的其他進行掛起,GC程式會獨佔CPU,長時間的GC操作或頻繁GC就會導致其他程式長時間分配不到CPU時間片,這就是導致渲染變慢的根本原因。我們點選HeapTaskDaemon顏色塊,可以看到具體的GC時間,如下圖所示:
在這裡插入圖片描述

操作快捷鍵

  • W、S:放大、縮小
  • A、D:向左、向右移動

 需要注意的是,由於Systrace是以系統的角度返回一些資訊,只能提供一個大概且深度有限,我們可以用它來進行粗略的檢查,以便獲得具體分析的方向。如果需要進一步得到是哪塊程式碼引起的CPU繁忙、某些方法的呼叫次數等,就需要藉助TraceView這個工具進行。

2.2.2 TraceView

TraceView是Android SDK中自帶的資料採集和分析工具,與Systrace不同的是,它是從程式碼層面來分析效能問題,且針對的是每個方法來分析,比如當我們發現應用出現卡頓的時候,就可以通過TraceVIew來分析出現卡頓時在方法的呼叫上有沒有很耗時的操作。開啟TraceView方法與Systrace一樣,都是在DDMS中啟動。在使用TraceView時,我們需要著重關注以下兩個方面:

  • 呼叫次數不多,但是每一個執行都很耗時;
  • 方法耗時不大,但是呼叫次數太多;

TraceView使用方法:

  1. 雙擊sdk目錄/tools/monitor.bat開啟DDMS,單擊DDMS皮膚上左上角帶小紅點按鈕,文字提示為start Method Profiling,然後按鈕左上方會出現一個灰色的正方形,文字提示為stop Method Profiling,此時按鈕變為停止採集功能;
  2. 進入Profiling Options配置取樣頻率,預設為1000微秒;
  3. 操作APP我們懷疑卡頓的地方,對該過程進行跟蹤;
  4. 操作結束後再次點選之前的按鈕(文字提示stop Method Profiling)結束採集。
    在這裡插入圖片描述
     從上圖可以看出,TraceView的皮膚分上下兩個部分:
  • 時間線皮膚以每個執行緒為一行,右邊是該執行緒在整個過程中方法執行的情況;
  • 資料分析皮膚是以表格的形式展示所有執行緒的方法的各項資料指標;

時間線皮膚:

 時間線皮膚以每個執行緒為一行,右邊是該執行緒在整個過程中方法執行的情況,比如上圖中顯示的main執行緒就是Android應用的主執行緒,當然也會存在其他執行緒,可能會因操作不同而發生改變。每個執行緒的右邊對應的是該執行緒中每個方法的執行資訊,左邊為第一個方法執行開始,最右邊為最後一個方法執行結束,其中的每一個小立柱就代表一次方法的呼叫,你可以把滑鼠放到立柱上,就會顯示該方法呼叫的詳細資訊。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-57KrViMV-1574213695825)(F:\360MoveData\Users\Jiangdg\Desktop\效能優化\插圖\APK12.png)]

 如上圖所示,墨綠色的立柱表示FibonacciActivity.computeFubonacci()方法的執行情況,可以看出這個方法執行的時間很長,尤其是對於處於主執行緒中,這是非常不正常的現象。如果你想在分析皮膚中詳細檢視該方法,可以雙擊該立柱,資料分析皮膚自動跳轉到該方法。

資料分析皮膚:

 資料分析皮膚右側為時間線皮膚中每個立柱表示的方法,當我點選墨綠色立柱後,FibonacciActivity.computeFubonacci()方法被高亮,展開該方法我們可以看到ParentsChildren,其中,Parents表示誰呼叫了computeFubonacci()方法,Children表示computeFubonacci()方法呼叫了哪些方法。資料分析皮膚的左側展示的是每個方法(一行)執行的耗時,我們著重看下computeFubonacci()方法Incl Real Time值為1595.360ms,這顯然是不正常的。另外,再看下Calls+Recur Calls/Total的值顯示computeFubonacci()方法數為1,但是被遞迴呼叫了1491次。因此,我們就可以得出之前的APP操作之所以會出現卡頓,是因為在主執行緒的FibonacciActivity中遞迴呼叫了computeFubonacci()方法,導致CPU被長期佔用,從而導致渲染執行緒無法獲得CPU資源出現無法正常渲染的效能問題。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-RKq6Y0q2-1574213695825)(F:\360MoveData\Users\Jiangdg\Desktop\效能優化\插圖\APK13.png)]

 每一列資料代表的含義如下表所示:

名稱 意義
Name 方法的詳細資訊,包括包名和引數資訊
Incl Cpu Time Cpu執行該方法該方法及其子方法所花費的時間
Incl Cpu Time % Cpu執行該方法該方法及其子方法所花費佔Cpu總執行時間的百分比
Excl Cpu Time Cpu執行該方法所話費的時間
Excl Cpu Time % Cpu執行該方法所話費的時間佔Cpu總時間的百分比
Incl Real Time 該方法及其子方法執行所話費的實際時間
Incl Real Time % 上述時間佔總的執行時間的百分比
Excl Real Time % 該方法自身的實際允許時間
Excl Real Time 上述時間佔總的允許時間的百分比
Calls+Recur Calls/Total 呼叫次數+遞迴次數
Calls/Total 呼叫次數和總次數的佔比
Cpu Time/Call Cpu執行時間和呼叫次數的百分比,代表該函式消耗cpu的平均時間
Real Time/Call 實際時間於呼叫次數的百分比,該表該函式平均執行時間
  • FibonacciActivity原始碼如下:
/** UI卡頓現象
 * @Auther: Jiangdg
 * @Date: 2019/11/18 15:06
 * @Description: 使用斐波那契數列人為製造卡頓現象
 */
public class FibonacciActivity extends AppCompatActivity {
    private static final String LOG_TAG = "FibonacciActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fibonacci);

        Button mbtn = (Button) findViewById(R.id.caching_do_fib_stuff);
        mbtn.setText("計算斐波那契數列");

        mbtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(LOG_TAG, String.valueOf(computeFibonacci(40)));
            }
        });
        WebView webView = (WebView) findViewById(R.id.webview);
        webView.getSettings().setUseWideViewPort(true);
        webView.getSettings().setLoadWithOverviewMode(true);
        webView.loadUrl("file:///android_asset/shiver_me_timbers.gif");
    }

    public int computeFibonacci(int positionInFibSequence) {
        //0 1 1 2 3 5 8
        if (positionInFibSequence <= 2) {
            return 1;
        } else {
            return computeFibonacci(positionInFibSequence - 1)
                    + computeFibonacci(positionInFibSequence - 2);
        }
    }
}

相關文章