Android小知識-瞭解下Android系統的顯示原理
在Android系統中應用層負責繪製,系統層負責渲染,通過程序間通訊把應用層需要繪製的資料傳遞到系統層,系統層服務通過重新整理機制把資料更新到螢幕上,圖形顯示系統採用的是C/S架構。
Android中View繪製需要三個步驟,通過Measure和Layout來確定當前需要繪製的View所在的大小和位置,接著通過Draw繪製到suface。
Measure用深度優先原則遞迴得到所有檢視的寬和高,獲取當前View的正確寬度childWidthMeasureSpec和高度childHeightMeasureSpec之後,可以呼叫它的成員函式Measure來設定大小。如果當前正在測量的子檢視是一個檢視容器,那麼它又會重複執行操作,直到它的所有子孫檢視的大小測量完成為止。Layout也是採用深度優先原則遞迴得到所有檢視的位置,當子View在應用程式視窗左上角的位置確定後,再結合它在前面測量過程中確定的寬度和高度,就可以完全確定它在應用程式視窗中的佈局。Draw採用兩種繪製方式,分別是軟體繪製(CPU)和硬體加速(GPU),硬體加速是在Android 3.0開始採用的。
硬體加速的優點是UI的顯示和繪製的效率高於CPU繪製,但它也存在明顯的缺點,GPU的功耗比CPU高,造成耗電問題;某些介面和函式不支援硬體加速,造成相容問題;使用OpenGL的介面至少需要8MB記憶體,造成記憶體過大問題。
將資料渲染到螢幕上,是通過系統級程序中的SufaceFlinger服務來實現的,應用層繪製到快取區,SufaceFlinger把快取區資料渲染到螢幕,由於是兩個不同的程序,所以Android的匿名共享記憶體SharedClient快取需要顯示的資料來達到目的。
FPS代表每秒傳遞的幀數,Android系統每隔16ms發出VSYNC(垂直中斷)訊號,觸發對UI進行渲染,如果每次渲染都成功,這樣就能達到流暢的畫面所需的60FPS。如果未能在16ms內發出訊號,觸發對UI進行渲染,就會造成丟幀現象,使用者會感到卡頓不流暢。
Android 4.1版本推出了Project Butter。Project Butter對Android Display進行了重構,引入三個核心元素:VSYNC、Triple Buffer和Choreographer。
VSYNC是一種定時中斷,一旦受到VSYNC中斷,CPU就開始處理各幀資料。Choreographer起一個排程的作用,將繪製工作統一到VSYNC某個時間點上,使應用的繪製工作有序。Triple Buffer是第三塊繪製的Buffer,減少顯示內容的延遲,之前採用的是雙緩衝,所謂的雙緩衝就是使用兩個緩衝區,其中一個稱為Front Buffer,另外一個成為Back Buffer,UI在Back Buffer中繪製,然後再和Front Buffer交換,渲染到顯示裝置中,當兩個Buffer不夠用時,就會採用三級緩衝來增強。
下圖是Android 4.1之前未加入VSYNC的繪製流程圖:

20131115192829593.png
Display顯示第0幀資料,此時CPU和GPU渲染第1幀畫面,而且趕在Display顯示下一幀前完成,因為渲染及時,Display在第0幀顯示完成後,也就是第1個VSync後,正常顯示第1幀。
由於某些原因,比如CPU資源被佔用,系統沒有及時地開始處理第2幀,直到第2個VSync快來前才開始處理 ,第2個VSync來時,由於第2幀資料還沒有準備就緒,顯示的還是第1幀。就出現了所謂的“Jank”。
當第2幀資料準備完成後,它並不會馬上被顯示,而是要等待下一個VSync。
下圖是Android 4.1加入VSYNC的繪製流程圖:

20130521133802421.png
CPU/GPU根據VSYNC訊號同步處理資料,可以讓CPU/GPU有完整的16ms時間來處理資料,減少了jank。
雙緩衝下當CPU和GPU處理時間過長時流程圖如下:

20130521133902544.png
當CPU/GPU的處理時間超過16ms時,在第二個16ms時間段內,Display應該顯示B幀,但因為GPU還在處理B幀,導致A幀重複顯示。並且在第二個16ms內,CPU什麼事情都做不了,這是因為A Buffer由Display在使用,B Buffer由GPU在使用。
三級緩衝繪製圖如下:

20130521134114618_看圖王.png
當第一次VSync發生後,CPU不用再等待了,它會使用第三個buffer C來進行下一幀資料的準備工作。雖然對緩衝區C的處理所需時間同樣超過了16ms,但這並不影響顯示屏,第2次VSync到來後,它選擇buffer B進行顯示;而第3次VSync時,它會接著採用C,而不是像double buffering中所看到的情況一樣只能再顯示一遍B了。這樣子就有效地降低了jank。

838794-506ddad529df4cd4.webp.jpg
搜尋微信“顧林海”公眾號,定期推送優質文章。