Android圖形系統之Surface、SurfaceView、SurfaceHolder及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的主線程中更新畫面。

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);
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM