Android開發之SurfaceView

extends View

java.lang.Object

   ↳

android.view.View

 

   ↳

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場景。


關於SurfaceView的使用

被動更新畫面的。比如棋類,這種用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);
// 結束鎖定畫圖,並提交改變。


測試代碼:

[java] view plaincopy
  1. package com.blueeagle;  
  2.   
  3. import android.app.Activity;  
  4.  import android.content.Context;  
  5.  import android.graphics.Canvas;  
  6.  import android.graphics.Color;  
  7.  import android.graphics.Paint;  
  8.  import android.graphics.Rect;  
  9.  import android.os.Bundle;  
  10.  import android.view.SurfaceHolder;  
  11.  import android.view.SurfaceView;  
  12.    
  13. public class SurfaceView01 extends Activity {  
  14.      /** Called when the activity is first created. */  
  15.      @Override  
  16.      public void onCreate(Bundle savedInstanceState) {  
  17.          super.onCreate(savedInstanceState);  
  18.          setContentView(new MyView(this));  
  19.      }  
  20.      //視圖內部類  
  21.      class MyView extends SurfaceView implements SurfaceHolder.Callback  
  22.      {  
  23.          private SurfaceHolder holder;  
  24.          private MyThread myThread;   
  25.          public MyView(Context context) {  
  26.              super(context);  
  27.              // TODO Auto-generated constructor stub  
  28.              holder = this.getHolder();  
  29.              holder.addCallback(this);  
  30.              myThread = new MyThread(holder);//創建一個繪圖線程  
  31.          }  
  32.    
  33.          @Override  
  34.          public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  35.                  int height) {  
  36.              // TODO Auto-generated method stub  
  37.                
  38.          }  
  39.    
  40.          @Override  
  41.          public void surfaceCreated(SurfaceHolder holder) {  
  42.              // TODO Auto-generated method stub  
  43.              myThread.isRun = true;  
  44.              myThread.start();  
  45.          }  
  46.    
  47.          @Override  
  48.          public void surfaceDestroyed(SurfaceHolder holder) {  
  49.              // TODO Auto-generated method stub  
  50.              myThread.isRun = false;  
  51.          }  
  52.            
  53.      }  
  54.      //線程內部類  
  55.      class MyThread extends Thread  
  56.      {  
  57.          private SurfaceHolder holder;  
  58.          public boolean isRun ;  
  59.          public  MyThread(SurfaceHolder holder)  
  60.          {  
  61.              this.holder =holder;   
  62.              isRun = true;  
  63.          }  
  64.          @Override  
  65.          public void run()  
  66.          {  
  67.              int count = 0;  
  68.              while(isRun)  
  69.              {  
  70.                  Canvas c = null;  
  71.                  try  
  72.                  {  
  73.                      synchronized (holder)  
  74.                      {  
  75.                          c = holder.lockCanvas();//鎖定畫布,一般在鎖定後就可以通過其返回的畫布對象Canvas,在其上面畫圖等操作了。  
  76.                          c.drawColor(Color.BLACK);//設置畫布背景顏色  
  77.                          Paint p = new Paint(); //創建畫筆  
  78.                          p.setColor(Color.WHITE);  
  79.                          Rect r = new Rect(10050300250);  
  80.                          c.drawRect(r, p);  
  81.                          c.drawText("這是第"+(count++)+"秒"100310, p);  
  82.                          Thread.sleep(1000);//睡眠時間爲1秒  
  83.                      }  
  84.                  }  
  85.                  catch (Exception e) {  
  86.                      // TODO: handle exception  
  87.                      e.printStackTrace();  
  88.                  }  
  89.                  finally  
  90.                  {  
  91.                      if(c!= null)  
  92.                      {  
  93.                          holder.unlockCanvasAndPost(c);//結束鎖定畫圖,並提交改變。  
  94.    
  95.                      }  
  96.                  }  
  97.             }  
  98.          }  
  99.      }  
  100. }  

轉自:http://blog.csdn.net/windren06/article/details/8461234

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章