SurfaceView使用介紹

        轉載請註明:http://blog.csdn.net/zhangshuaizaxia/article/details/50476869,來自Davencheung的博客!

什麼是SurfaceView?

        其實在去年學習Android的APIDEMO的時候,有接觸到SurfaceView, 但是卻一直不是很明白他的作用,只知道他和View有一些區別。事實上,SurfaceView是繼承View。我們知道Android系統通過發出VSYNC信號來刷新屏幕,刷新的時間間隔爲16ms,也就是在有屏幕刷新的情況下,view的draw函數中的內容必須在16ms內完成,如果超出這個時間,就會出現掉幀。而SurfaceView何時刷新,則是可以控制的。

        下面是surfaceView的API的譯文(摘自網絡)

        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。

        另外,通過下面幾點,你可以確定何時選擇使用SurfaceView:

        1. View適用於主動更新的情況下,而SurfaceView適應於被動刷新,頻繁的刷新,例如遊戲界面;

        2. View在主線程中對畫面進行刷新,而SurfaceView通常會通過一個子線程來進行頁面的刷新;(可以在子線程中做大量的處理)

        3. View在繪圖的時候沒有使用雙緩存的機制,而SurfaceView在底層使用雙緩存的機制。

SurfaceView使用模板

        SurfaceView的使用是有規矩可以遵循,在《Android羣英會》一書中,作者給出了一個使用模板,使用起來很簡單!

package com.cheungshuai.surfaceview;

import java.util.Calendar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


/**
 * 
 * @author davencheung
 *
 */
public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable{

    private SurfaceHolder mHolder;
    private Canvas mCanvas;
    private boolean mIsDrawing;//whether is drawing
    
 
    public SurfaceViewTemplate(Context context) {
        super(context);
        initView();
    }
    
    public SurfaceViewTemplate(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public SurfaceViewTemplate(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


    private void initView(){
        mHolder = getHolder();
        mHolder.addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        setKeepScreenOn(true);
        //do something here!
        mPaint = new Paint();
        mPaint.setTextSize(50);
        mPaint.setColor(Color.RED);
        mPaint.setTextAlign(Align.CENTER);
    }

    private Calendar mCalendar;
    private Paint mPaint;
    private String mTime;
    @Override
    public void run() {
        while(mIsDrawing){
            draw();
        }
    }
    
    private void draw(){
        try{
            mCanvas = mHolder.lockCanvas();
            //do something here!
            mCanvas.drawColor(Color.WHITE);
            mCalendar = Calendar.getInstance();
            mTime = mCalendar.get(Calendar.HOUR_OF_DAY)+"時"+
                    mCalendar.get(Calendar.MINUTE)+"分"+
                    mCalendar.get(Calendar.SECOND)+"秒";
            mCanvas.drawText(mTime, getWidth()/2, getHeight()/2, mPaint);
        }catch(Exception e){
            
        }finally{
            if(mCanvas != null){
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mIsDrawing = true;
        new Thread(this).start();
        
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mIsDrawing = false;
    }
}
        基本上按照上面的使用方法,就可以完成很多事情。我們要做的就是在下面這行代碼下面添加一些自己的內容即可!
      //do something here!

        而在MainActiivity中只需要如下的處理:

    SurfaceViewTemplate sv = new SurfaceViewTemplate(this);
    setContentView(sv);

控制刷新間隔時間

        另外,我們可以在線程的run函數中控制線程的運行,然後是的刷新間隔時間改變。

        例如,修改下面的代碼,就可以讓界面每5秒刷新一次!

        while(mIsDrawing){
            draw();
            try{
                Thread.sleep(5000);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }

        記住,這個sleep需要在while循環調用,因爲,第一次運行之後,界面就一直通過這個循環來刷新,不會再走其他的流程,代碼無法執行到(Android羣英會中的示例應該有問題),直到退出應用!

        運行的效果圖如下:





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