SurfaceView不能直接使用,需要使用時需要基於他派生出我們自己的類,並匯出SurfaceHolder.Callback介面並實現。SurfaceView繼承於視圖類(View),能夠實現線程繪圖主要是因為其內部包含一個專門用於繪製的Surface。人們通過getHolder()獲得Surface的控制代碼,然後通過SurfaceHolder介面的callback來使用他。SurfaceHolder的使用周期與surfaceview有關,surfaceview可見時,surface被建立;surfaceview不可見時,surface被銷毀,且在surfaceview不可見之前。這樣設計大概是基於節省資源考慮。surfaceview的核心提供了兩個線程:UI線程和渲染線程。所有SurfaceView和SurfaceHolder.Callback的方法都應該在UI線程裡調用,一般來說就是應用程式主線程。渲染線程所要訪問的各種變數應該作同步處理。由於surface可能被銷毀,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之間有效,所以要確保渲染線程訪問的是合法有效surface。而我們的一些資源變數初始化和釋放也盡量在這兩個線方法之中。
調用SurfaceHolder需要重載這三個方法,然後通過lockCanvas方法獲得畫布繪圖,繪結束後使用unlockCanvasAndPost提交給前台視窗重新整理。流程是先獲得SurfaceHolder,然後添加回調,實現三個介面,最後在lockCanvas和unlockCanvasAndPost之間實現代碼.
SurfaceView是視圖(View)的繼承類,這個視圖裡內嵌了一個專門用於繪製的Surface。你可以控制這個Surface的格式和尺寸。Surfaceview控制這個Surface的繪製位置。
surface是縱深排序(Z-ordered)的,這表明它總在自己所在視窗的後面。surfaceview提供了一個可見地區,只有在這個可見地區內 的surface部分內容才可見,可見地區外的部分不可見。surface的排版顯示受到視圖層級關係的影響,它的兄弟視圖結點會在頂端顯示。這意味者 surface的內容會被它的兄弟視圖遮擋,這一特性可以用來放置遮蓋物(overlays)(例如,文本和按鈕等控制項)。注意,如果surface上面 有透明控制項,那麼它的每次變化都會引起架構重新計算它和頂層控制項的透明效果,這會影響效能。
你可以通過SurfaceHolder介面訪問這個surface,getHolder()方法可以得到這個介面。
surfaceview變得可見時,surface被建立;surfaceview隱藏前,surface被銷毀。這樣能節省資源。如果你要查看 surface被建立和銷毀的時機,可以重載surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在於提供了兩個線程:UI線程和渲染線程。這裡應注意:
1> 所有SurfaceView和SurfaceHolder.Callback的方法都應該在UI線程裡調用,一般來說就是應用程式主線程。渲染線程所要訪問的各種變數應該作同步處理。
2> 由於surface可能被銷毀,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之間有效,所以要確保渲染線程訪問的是合法有效surface。
接下來呢,說說自己對它的理解
1、定義
可以直接從記憶體或者DMA等硬體介面取得映像資料,是個非常重要的繪圖容器。
它的特性是:可以在主線程之外的線程中向螢幕繪圖上。這樣可以避免畫圖任務繁重的時候造成主線程阻塞,從而提高了程式的反應速度。在遊戲開發中多用到SurfaceView,遊戲中的背景、人物、動畫等等盡量在畫布canvas中畫出。
2、實現
首先繼承SurfaceView並實現SurfaceHolder.Callback介面
使用介面的原因:因為使用SurfaceView 有一個原則,所有的繪圖工作必須得在Surface 被建立之後才能開始(Surface—表面,這個概念在 圖形編程中常常被提到。基本上我們可以把它當作顯存的一個映射,寫入到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)結束鎖定畫圖,並提交改變,將圖形顯示。
3、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);
// 結束鎖定畫圖,並提交改變。
4、執行個體
這裡的例子實現了一個矩形和一個計時器
?
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
View Code package xl.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; public class ViewTest extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView( new MyView( this )); } //視圖內部類 class MyView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private MyThread myThread; public MyView(Context context) { super (context); // TODO Auto-generated constructor stub holder = this .getHolder(); holder.addCallback( this ); myThread = new MyThread(holder); //建立一個繪圖線程 } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub myThread.isRun = true ; myThread.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub myThread.isRun = false ; } } //線程內部類 class MyThread extends Thread { private SurfaceHolder holder; public boolean isRun ; public MyThread(SurfaceHolder holder) { this .holder =holder; isRun = true ; } @Override public void run() { int count = 0 ; while (isRun) { Canvas c = null ; try { synchronized (holder) { c = holder.lockCanvas(); //鎖定畫布,一般在鎖定後就可以通過其返回的畫布對象Canvas,在其上面畫圖等操作了。 c.drawColor(Color.BLACK); //設定畫布背景顏色 Paint p = new Paint(); //建立畫筆 p.setColor(Color.WHITE); Rect r = new Rect( 100 , 50 , 300 , 250 ); c.drawRect(r, p); c.drawText( "這是第" +(count++)+ "秒" , 100 , 310 , p); Thread.sleep( 1000 ); //睡眠時間為1秒 } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { if (c!= null ) { holder.unlockCanvasAndPost(c); //結束鎖定畫圖,並提交改變。 } } } } } } |