1. 程式人生 > >Android之——Surface、SurfaceView與SurfaceHolder.Callback初探

Android之——Surface、SurfaceView與SurfaceHolder.Callback初探

一、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中的內容。流程為:

   1:建立一個Bitmap物件。

     2:建立一個Canvas物件關聯建立的Bitmap物件。

     3:在Canvas上進行繪製。

     4:鎖定Canvas畫布。

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

     6:解鎖Canvas畫布。

二、SurfaceView    SurfaceView是檢視類View的子類,且實現了Parcelable介面且實現了Parcelable介面,其中內嵌了一個專門用於繪製的Surface,SurfaceView可以控制這個Surface的格式和尺寸,以及Surface的繪製位置。可以理解為Surface就是管理資料的地方,SurfaceView就是展示資料的地方。

三、SurfaceHolder    SurfaceHolder是一個介面,類似於一個surace的監聽器。通過下面三個回撥方法監聽Surface的建立、銷燬或者改變。

    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中的資料完成後,釋放同步鎖,並提交改變,然後將新的資料進行展示。

四、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的例子:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.BitmapDrawable;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder.Callback;
 
public class MySurfaceView extends SurfaceView implements Runnable, Callback {
    private SurfaceHolder mHolder; // 用於控制SurfaceView
    private Thread t; // 宣告一條執行緒
    private volatile boolean flag; // 執行緒執行的標識,用於控制執行緒
    private Canvas mCanvas; // 宣告一張畫布
    private Paint p; // 宣告一支畫筆
    float m_circle_r = 10;
 
    public MySurfaceView(Context context) {
        super(context);
 
        mHolder = getHolder(); // 獲得SurfaceHolder物件
        mHolder.addCallback(this); // 為SurfaceView新增狀態監聽
        p = new Paint(); // 建立一個畫筆物件
        p.setColor(Color.WHITE); // 設定畫筆的顏色為白色
        setFocusable(true); // 設定焦點
    }
 
    /**
     * 當SurfaceView建立的時候,呼叫此函式
     */
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        t = new Thread(this); // 建立一個執行緒物件
        flag = true; // 把執行緒執行的標識設定成true
        t.start(); // 啟動執行緒
    }
 
    /**
     * 當SurfaceView的檢視發生改變的時候,呼叫此函式
     */
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }
 
    /**
     * 當SurfaceView銷燬的時候,呼叫此函式
     */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        flag = false; // 把執行緒執行的標識設定成false
        mHolder.removeCallback(this);
    }
 
    /**
     * 當螢幕被觸控時呼叫
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
 
        return true;
    }
 
    /**
     * 當用戶按鍵時呼叫
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
        }
        return super.onKeyDown(keyCode, event);
    }
 
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        surfaceDestroyed(mHolder);
        return super.onKeyDown(keyCode, event);
    }
 
    @Override
    public void run() {
        while (flag) {
            try {
                synchronized (mHolder) {
                    Thread.sleep(100); // 讓執行緒休息100毫秒
                    Draw(); // 呼叫自定義畫畫方法
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (mCanvas != null) {
                    // mHolder.unlockCanvasAndPost(mCanvas);//結束鎖定畫圖,並提交改變。
 
                }
            }
        }
    }
 
    /**
     * 自定義一個方法,在畫布上畫一個圓
     */
    protected void Draw() {
        mCanvas = mHolder.lockCanvas(); // 獲得畫布物件,開始對畫布畫畫
        if (mCanvas != null) {
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setColor(Color.BLUE);
            paint.setStrokeWidth(10);
            paint.setStyle(Style.FILL);
            if (m_circle_r >= (getWidth() / 10)) {
                m_circle_r = 0;
            } else {
                m_circle_r++;
            }
            Bitmap pic = ((BitmapDrawable) getResources().getDrawable(
                    R.drawable.qq)).getBitmap();
            mCanvas.drawBitmap(pic, 0, 0, paint);
            for (int i = 0; i < 5; i++)
                for (int j = 0; j < 8; j++)
                    mCanvas.drawCircle(
                            (getWidth() / 5) * i + (getWidth() / 10),
                            (getHeight() / 8) * j + (getHeight() / 16),
                            m_circle_r, paint);
            mHolder.unlockCanvasAndPost(mCanvas); // 完成畫畫,把畫布顯示在螢幕上
        }
    }
}