SurfaceView 教程

SurfaceView介紹
通常情況程序的View和用戶響應都是在同一個線程中處理的,這也是爲什麼處理長時間事件(例如訪問網絡)需要放到另外的線程中去(防止阻塞當前UI線程的操作和繪製)。但是在其他線程中卻不能修改UI元素,例如用後臺線程更新自定義View(調用View的在自定義View中的onDraw函數)是不允許的。
 
如果需要在另外的線程繪製界面、需要迅速的更新界面或則渲染UI界面需要較長的時間,這種情況就要使用SurfaceView了。SurfaceView中包含一個Surface對象,而Surface是可以在後臺線程中繪製的。Surface屬於
 
OPhone底層顯示系統,關於這方面的介紹請參考附錄中的資料[1]。SurfaceView的性質決定了其比較適合一些場景:需要界面迅速更新、對幀率要求較高的情況。使用SurfaceView需要注意以下幾點情況:
SurfaceView和SurfaceHolder.Callback函數都從當前SurfaceView窗口線程中調用(一般而言就是程序的主線程)。有關資源狀態要注意和繪製線程之間的同步。 
 在繪製線程中必須先合法的獲取Surface才能開始繪製內容,在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之間的狀態爲合法的,另外在Surface類型爲SURFACE_TYPE_PUSH_BUFFERS時候是不合法的。 
 額外的繪製線程會消耗系統的資源,在使用SurfaceView的時候要注意這點。 
 
使用SurfaceView
只要繼承SurfaceView類並實現SurfaceHolder.Callback接口就可以實現一個自定義的SurfaceView了,SurfaceHolder.Callback在底層的Surface狀態發生變化的時候通知View,SurfaceHolder.Callback具有如下的接口:
 surfaceCreated(SurfaceHolder holder):當Surface第一次創建後會立即調用該函數。程序可以在該函數中做些和繪製界面相關的初始化工作,一般情況下都是在另外的線程來繪製界面,所以不要在這個函數中繪製Surface。 
 surfaceChanged(SurfaceHolder holder, int format, int width,int height):當Surface的狀態(大小和格式)發生變化的時候會調用該函數,在surfaceCreated調用後該函數至少會被調用一次。 
 surfaceDestroyed(SurfaceHolder holder):當Surface被摧毀前會調用該函數,該函數被調用後就不能繼續使用Surface了,一般在該函數中來清理使用的資源。 
 
通過SurfaceView的getHolder()函數可以獲取SurfaceHolder對象,Surface 就在SurfaceHolder對象內。雖然Surface保存了當前窗口的像素數據,但是在使用過程中是不直接和Surface打交道的,由SurfaceHolder的Canvas lockCanvas()或則Canvas lockCanvas(Rect dirty)函數來獲取Canvas對象,通過在Canvas上繪製內容來修改Surface中的數據。如果Surface不可編輯或則尚未創建調用該函數會返回null,在 unlockCanvas() 和 lockCanvas()中Surface的內容是不緩存的,所以需要完全重繪Surface的內容,爲了提高效率只重繪變化的部分則可以調用lockCanvas(Rect dirty)函數來指定一個dirty區域,這樣該區域外的內容會緩存起來。在調用lockCanvas函數獲取Canvas後,SurfaceView會獲取Surface的一個同步鎖直到調用unlockCanvasAndPost(Canvas canvas)函數才釋放該鎖,這裏的同步機制保證在Surface繪製過程中不會被改變(被摧毀、修改)。
當在Canvas中繪製完成後,調用函數unlockCanvasAndPost(Canvas canvas)來通知系統Surface已經繪製完成,這樣系統會把繪製完的內容顯示出來。爲了充分利用不同平臺的資源,發揮平臺的最優效果可以通過SurfaceHolder的setType函數來設置繪製的類型,目前接收如下的參數:
SURFACE_TYPE_NORMAL:用RAM緩存原生數據的普通Surface 
SURFACE_TYPE_HARDWARE:適用於DMA(Direct memory access )引擎和硬件加速的Surface 
SURFACE_TYPE_GPU:適用於GPU加速的Surface 
SURFACE_TYPE_PUSH_BUFFERS:表明該Surface不包含原生數據,Surface用到的數據由其他對象提供,在Camera圖像預覽中就使用該類型的Surface,有Camera負責提供給預覽Surface數據,這樣圖像預覽會比較流暢。如果設置這種類型則就不能調用lockCanvas來獲取Canvas對象了。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章