Android圖形系統之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之間的聯繫

1、Surface

   Surface在SDK的文檔中的描述是這樣的:Handle onto a raw buffer that is being managed by the screen compositor,Android中的Surface就是一個用來畫圖形(graphics)或圖像(image)的地方,對於View及其子類,都是畫在Surface上,各Surface對象經過Surfaceflinger合成到frameBuffer,每一個Surface都是雙緩衝,它有一個backBuffer和一個frontBuffer,Surface中建立了Canvas對象,用來管理Surface繪圖操做,Canvas對應Bitmap,存儲Surface中的內容。流程爲:java

   1:建立一個Bitmap對象。android

     2:建立一個Canvas對象關聯建立的Bitmap對象。canvas

     3:在Canvas上進行繪製。app

     4:鎖定Canvas畫布。ide

     5:將Bitmap內容繪製到backBuffer中去。函數

     6:解鎖Canvas畫布。this

2、SurfaceView

   SurfaceView是視圖類View的子類,且實現了Parcelable接口且實現了Parcelable接口,其中內嵌了一個專門用於繪製的Surface,SurfaceView能夠控制這個Surface的格式和尺寸,以及Surface的繪製位置。能夠理解爲Surface就是管理數據的地方,SurfaceView就是展現數據的地方。spa

3、SurfaceHolder

   SurfaceHolder是一個接口,相似於一個surace的監聽器。經過下面三個回調方法監聽Surface的建立、銷燬或者改變。.net

    SurfaceView中調用getHolder方法,能夠得到當前SurfaceView中的surface對應的SurfaceHolder,SurfaceHolder中重要的方法有:線程

    1: abstract  void addCallback(SurfaceHolder.Callback callback );爲SurfaceHolder添加一個SurfaceHolder.Callback回調接口。

   2:  abstract  Canvas lockCanvas() ;獲取Surface中的Canvas對象,並鎖定之。所獲得的Canvas對象。

    3:abstract  void unlockCanvasAndPost(Canvas canvas);當修改Surface中的數據完成後,釋放同步鎖,並提交改變,而後將新的數據進行展現

4、SurfaceHolder.Callback

   SurfaceHolder.Callback是SurfaceHolder接口內部的靜態子接口,SurfaceHolder.Callback中定義了三個接口方法:
   1:public void sufaceChanged(SurfaceHolder holder,int format,int width,int height){}//Surface的大小發生改變時調用。
   2: public void surfaceCreated(SurfaceHolder holder){}//Surface建立時激發,通常在這裏調用畫面的線程。
   3: public void surfaceDestroyed(SurfaceHolder holder){}//銷燬時激發,通常在這裏將畫面的線程中止、釋放。

    SurfaceView和View最本質的區別在於:SurfaceView是在一個新起的單獨線程中能夠從新繪製畫面而View必須在UI的主線程中更新畫面。下面是SurfaceView的例子:

  1. import android.content.Context;  
  2. import android.graphics.Bitmap;  
  3. import android.graphics.Canvas;  
  4. import android.graphics.Color;  
  5. import android.graphics.Paint;  
  6. import android.graphics.Paint.Style;  
  7. import android.graphics.drawable.BitmapDrawable;  
  8. import android.view.SurfaceHolder;  
  9. import android.view.SurfaceView;  
  10. import android.view.KeyEvent;  
  11. import android.view.MotionEvent;  
  12. import android.view.SurfaceHolder.Callback;  
  13.   
  14. public class MySurfaceView extends SurfaceView implements Runnable, Callback {  
  15.     private SurfaceHolder mHolder; // 用於控制SurfaceView  
  16.     private Thread t; // 聲明一條線程  
  17.     private volatile boolean flag; // 線程運行的標識,用於控制線程  
  18.     private Canvas mCanvas; // 聲明一張畫布  
  19.     private Paint p; // 聲明一支畫筆  
  20.     float m_circle_r = 10;  
  21.   
  22.     public MySurfaceView(Context context) {  
  23.         super(context);  
  24.   
  25.         mHolder = getHolder(); // 得到SurfaceHolder對象  
  26.         mHolder.addCallback(this); // 爲SurfaceView添加狀態監聽  
  27.         p = new Paint(); // 建立一個畫筆對象  
  28.         p.setColor(Color.WHITE); // 設置畫筆的顏色爲白色  
  29.         setFocusable(true); // 設置焦點  
  30.     }  
  31.   
  32.     /** 
  33.      * 當SurfaceView建立的時候,調用此函數 
  34.      */  
  35.     @Override  
  36.     public void surfaceCreated(SurfaceHolder holder) {  
  37.         t = new Thread(this); // 建立一個線程對象  
  38.         flag = true; // 把線程運行的標識設置成true  
  39.         t.start(); // 啓動線程  
  40.     }  
  41.   
  42.     /** 
  43.      * 當SurfaceView的視圖發生改變的時候,調用此函數 
  44.      */  
  45.     @Override  
  46.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  47.             int height) {  
  48.     }  
  49.   
  50.     /** 
  51.      * 當SurfaceView銷燬的時候,調用此函數 
  52.      */  
  53.     @Override  
  54.     public void surfaceDestroyed(SurfaceHolder holder) {  
  55.         flag = false; // 把線程運行的標識設置成false  
  56.         mHolder.removeCallback(this);  
  57.     }  
  58.   
  59.     /** 
  60.      * 當屏幕被觸摸時調用 
  61.      */  
  62.     @Override  
  63.     public boolean onTouchEvent(MotionEvent event) {  
  64.   
  65.         return true;  
  66.     }  
  67.   
  68.     /** 
  69.      * 當用戶按鍵時調用 
  70.      */  
  71.     @Override  
  72.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  73.         if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {  
  74.         }  
  75.         return super.onKeyDown(keyCode, event);  
  76.     }  
  77.   
  78.     @Override  
  79.     public boolean onKeyUp(int keyCode, KeyEvent event) {  
  80.         surfaceDestroyed(mHolder);  
  81.         return super.onKeyDown(keyCode, event);  
  82.     }  
  83.   
  84.     @Override  
  85.     public void run() {  
  86.         while (flag) {  
  87.             try {  
  88.                 synchronized (mHolder) {  
  89.                     Thread.sleep(100); // 讓線程休息100毫秒  
  90.                     Draw(); // 調用自定義畫畫方法  
  91.                 }  
  92.             } catch (InterruptedException e) {  
  93.                 e.printStackTrace();  
  94.             } finally {  
  95.                 if (mCanvas != null) {  
  96.                     // mHolder.unlockCanvasAndPost(mCanvas);//結束鎖定畫圖,並提交改變。  
  97.   
  98.                 }  
  99.             }  
  100.         }  
  101.     }  
  102.   
  103.     /** 
  104.      * 自定義一個方法,在畫布上畫一個圓 
  105.      */  
  106.     protected void Draw() {  
  107.         mCanvas = mHolder.lockCanvas(); // 得到畫布對象,開始對畫布畫畫  
  108.         if (mCanvas != null) {  
  109.             Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  110.             paint.setColor(Color.BLUE);  
  111.             paint.setStrokeWidth(10);  
  112.             paint.setStyle(Style.FILL);  
  113.             if (m_circle_r >= (getWidth() / 10)) {  
  114.                 m_circle_r = 0;  
  115.             } else {  
  116.                 m_circle_r++;  
  117.             }  
  118.             Bitmap pic = ((BitmapDrawable) getResources().getDrawable(  
  119.                     R.drawable.qq)).getBitmap();  
  120.             mCanvas.drawBitmap(pic, 0, 0, paint);  
  121.             for (int i = 0; i < 5; i++)  
  122.                 for (int j = 0; j < 8; j++)  
  123.                     mCanvas.drawCircle(  
  124.                             (getWidth() / 5) * i + (getWidth() / 10),  
  125.                             (getHeight() / 8) * j + (getHeight() / 16),  
  126.                             m_circle_r, paint);  
  127.             mHolder.unlockCanvasAndPost(mCanvas); // 完成畫畫,把畫布顯示在屏幕上  
  128.         }  
  129.     }  
相關文章
相關標籤/搜索