如果做遊戲或者視訊相關開發的時候,将會用到surfaceview。對于surfaceview,首先需要了解一下它自己的位置:
<a target="_blank">java.lang.object</a>
<a target="_blank">android.view.view</a>
android.view.surfaceview
由手冊可知:
surfaceview是view類的繼承類,這個view裡内嵌了一個專門用于繪制的surface,這個可以類似的了解成為一個在view裡的canvas。你可以控制這個surface的格式和尺寸。surfaceview類則控制這個surface在螢幕上的正确位置。
《android進階程式設計》裡這樣說:
在一般情況下,應用程式的view都是在相同的gui線程中繪制的。這個主應用程式線程同時也用來處理所有的使用者互動(例如按鈕單擊或者文本輸入)。
對于一個view的ondraw()方法,不能夠滿足将其移動到背景線程中去。因為從背景線程修改一個gui元素會被顯式地禁止的。
當需要快速地更新view的ui,或者目前渲染代碼阻塞gui線程的時間過長的時候,surfaceview就是解決上述問題的最佳選擇。surfaceview封裝了一個surface對象,而不是canvas。這一點很重要,因為surface可以使用背景線程繪制。對于那些資源敏感的操作,或者那些要求快速更新或者高速幀率的地方,例如使用3d圖形,建立遊戲,或者實時預覽攝像頭,這一點特别有用。
1. 何時應該使用surfaceview
surfaceview使用的方式與任何view所派生的類都是完全相同的。可以像其他view那樣應用動畫,并把它們放到布局中。
surfaceview封裝的surface支援所有标準的canvas方法進行繪圖,同時也支援完全的opengl es 庫。
使用opengl,你可以在surface上繪制任何支援2d或者3d對象,與在2d畫布上模拟相同的效果相比,這種方法可以依靠硬體加速(可用的時候)來極大地提高性能。
對于顯示動态的3d圖像來說,例如,那些使用google earth 功能的應用程式,或者那些提供沉浸體驗的互動式遊戲,surface特别有用。它還是實時顯示攝像頭預覽的最佳選擇。
2. 建立一個新的surfaceview控件
建立一個新的surfaceview控件需要建立一個新的擴充了surfaceview的類,并實作surfaceholder.callback。
surfaceholder回調可以在底層的surface被建立和銷毀的時候通知view,并傳遞給它surfaceholder對象的引用,其中包含了目前有效的surface。
一個典型的surfaceview 設計模型包括一個由thread所派生的類,它可以接收對目前的surfaceholder的引用,并獨立地更新它。
3. 使用surfaceview建立3d控件
android完全支援opengl es 3d 渲染架構,其中包含了對裝置的硬體加速的支援。surfaceview控件提供了一個表面,可以在它上面渲染你的opengl場景。
那麼我們在使用的時候可以這樣使用:
被動更新畫面的。比如棋類,這種用view就好了。因為畫面的更新是依賴于 ontouch 來更新,可以直接使用 invalidate。 因為這種情況下,這一次touch和下一次的touch需要的時間比較長些,不會産生影響。
主動更新。比如一個人在一直跑動。這就需要一個單獨的thread不停的重繪人的狀态,避免阻塞main ui thread。是以顯然view不合适,需要surfaceview來控制。
可以直接從記憶體或硬體裝置比如相機等取得圖像資料,是個非常重要的繪圖容器。
它的特性是:可以在主線程之外的線程中向螢幕繪圖。這樣可以避免畫圖任務繁重的時候造成主線程阻塞,進而提高了程式的反應速度。
如何去使用一個surfaceview:
首先繼承surfaceview并實作surfaceholder.callback接口。因為使用surfaceview 有一個原則,所有的繪圖工作必須得在surface 被建立之後才能開始。可以被直接複制到顯存進而顯示出來,這使得顯示速度會非常快,而在surface 被銷毀之前必須結束。是以callback 中的surfacecreated 和surfacedestroyed 就成了繪圖處理代碼的邊界。
需要重寫的方法
(1)public void surfacechanged(surfaceholder holder,int format,int width,int height){}
//在surface的大小發生改變時激發
(2)public void surfacecreated(surfaceholder holder){}
//在建立時激發,一般在這裡調用畫圖的線程。
(3)public void surfacedestroyed(surfaceholder holder) {}
//銷毀時激發,一般在這裡将畫圖的線程停止、釋放。
整個過程:繼承surfaceview并實作surfaceholder.callback接口 ----> surfaceview.getholder()獲得surfaceholder對象 ---->surfaceholder.addcallback(callback)添加回調函數---->surfaceholder.lockcanvas()獲得canvas對象并鎖定畫布----> canvas繪畫 ---->surfaceholder.unlockcanvasandpost(canvas canvas)結束鎖定畫圖,并送出改變,将圖形顯示。
關于surfaceholder:
這裡用到了一個類surfaceholder,可以把它當成surface的控制器,用來操縱surface。處理它的canvas上畫的效果和動畫,控制表面,大小,像素等。
幾個需要注意的方法:
(1)、abstract void addcallback(surfaceholder.callback callback);
// 給surfaceview目前的持有者一個回調對象。
(2)、abstract canvas lockcanvas();
// 鎖定畫布,一般在鎖定後就可以通過其傳回的畫布對象canvas,在其上面畫圖等操作了。
(3)、abstract canvas lockcanvas(rect dirty);
// 鎖定畫布的某個區域進行畫圖等..因為畫完圖後,會調用下面的unlockcanvasandpost來改變顯示内容。
// 相對部分記憶體要求比較高的遊戲來說,可以不用重畫dirty外的其它區域的像素,可以提高速度。
(4)、abstract void unlockcanvasandpost(canvas canvas);
// 結束鎖定畫圖,并送出改變。
測試代碼如下:
轉自:http://blog.csdn.net/redoffice/article/details/6722067/