作者:沙茶醬
鏈接:/question/25811504/answer/31696269
來源:知乎
著作權歸作者所有,轉載請聯系作者獲得授權。
首先,對於CPU與GPU繪制的問題,根據google的文檔
/guide/topics/graphics/hardware-accel.html
安卓有2種繪制模型:
壹.軟件繪制模型,這裏由CPU主導繪圖,視圖按照以下2個步驟繪圖。
讓視圖結構(view hierarchy)失效。
繪制整個視圖結構。
當應用程序需要更新它的部分UI時,都會調用內容發生改變的View對象的invalidate()方法。無效(invalidation)消息請求會在View對象層次結構中傳遞,以便計算出需要重繪的屏幕區域(臟區)。然後,Android系統會在View層次結構中繪制所有的跟臟區相交的區域。但是,這種方法有兩個缺點:
1. 繪制了不需要重繪的視圖(與臟區域相交的區域)
2. 掩蓋了壹些應用的bug(由於會重繪與臟區域相交的區域)
註意:在View對象的屬性發生變化時,如背景色或TextView對象中的文本等,Android系統會自動的調用該View對象的invalidate()方法。
二.硬件加速繪制模型,這裏由GPU主導繪圖,視圖按照以下3個步驟繪圖。
讓視圖結構失效。
記錄和更新顯示列表(Display List)。
繪制顯示列表。
這種模式下,Android系統依然會使用invalidate()方法和draw()方法來請求屏幕更新和展現View對象。但Android系統並不是立即執行繪制命令,而是首先把這些View的繪制函數作為繪制指令記錄壹個顯示列表中,然後再讀取顯示列表中的繪制指令調用OpenGL相關函數完成實際繪制。另壹個優化是,Android系統只需要針對由invalidate()方法調用所標記的View對象的臟區進行記錄和更新顯示列表。沒有失效的View對象就簡單重用先前顯示列表記錄的繪制指令來進行簡單的重繪工作。
使用顯示列表的目的是,把視圖的各種繪制函數翻譯成繪制指令保存起來,對於沒有發生改變的視圖把原先保存的操作指令重新讀取出來重放壹次就可以了,提高了視圖的顯示速度。而對於需要重繪的View,則更新顯示列表,然後再調用OpenGL完成繪制。
在這種繪制模型下,我們不能依賴壹個視圖與臟區(dirty region)相交而導致它的draw()方法被自動調用,所以必須要手動調用該視圖的invalidate()方法去更新顯示列表。如果忘記這麽做可能導致視圖在改變後不會發生變化。
硬件加速提高了Android系統顯示和刷新的速度,但它也不是萬能的,它有三個缺陷:
1. 兼容性(部分繪制函數不支持或不完全硬件加速)
2. 內存消耗(OpenGL API調用就會占用8MB,而實際上會占用更多內存)
3. 電量消耗(GPU耗電)
第二個問題,關於SurfaceView,View,Canvas等問題,
參考安卓framework開發者Dianne Hackborn在stackoverflow給出的定義,
/questions/4576909/understanding-canvas-and-surface-concepts#answers
以及相關的PPT,下載鏈接如下:
/site/androidcontentfromchet/downloads/GraphicsandAnimations-Devoxx2010.pdf?attredirects=0