SurfaceView是继承View的派生类(public class SurfaceView extends View这个View里内嵌了一个专门用于绘制的Surface,这个可以类似的理解成为一个在View里的Canvas。你可以控制这个Surface的格式和尺寸。Surfaceview类则控制这个Surface在屏幕上的正确位置。

  在一般情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。
对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的,当需要快速地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。

3.如何使用使用一个SurfaceView,首先继承SurfaceView并实现SurfaceHolder.Callback接口。因为使用SurfaceView 有一个原则,所有的绘图工作必须得在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) {}
     //销毁时激发,一般在这里将画图的线程停止、释放。

4.下面举个在网上的一个被我改版的小球运动的例子

    a.MyPinBallSurfaceView类

public class MyPinBallSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{

    //桌面的宽度  
    private int tableWidth;  
    //桌面的高度  
    private int tableHeight;  
    //球拍的垂直位置  
    private int racketY;  
    //定义球拍的高度和宽度  
    private final int RACKET_HEIGHT = 20;  
    private final int RACKET_WIDTH = 70;  
    //小球的大小  
    private final int BALL_SIZE = 12;  
    //小球纵向的运行速度  
    private int ySpeed = 10;  
    Random rand = new Random();  
    //返回一个-0.5~0.5比率,用于控制小球的运行方向  
    private double xyRate = rand.nextDouble() - 0.5;  
    //小球横向的运行速度  
    private int xSpeed = (int)(ySpeed * xyRate * 2);  
    //ballX和ballY代表小球坐标  
    private int ballX = rand.nextInt(200) + 20;  
    private int ballY = rand.nextInt(10) + 20;  
    //racketX代表球拍的水平位置  
    private int racketX = rand.nextInt(200);  
    //游戏是否结束的旗标  
    private boolean isLose = false;
	
    private SurfaceHolder mSurfaceHolder;
    
    private boolean flag;//控制绘图结束的标示
    private Thread mThread;
    float x=0;
    
	public MyPinBallSurfaceView(Context context){
		super(context);
		mSurfaceHolder=this.getHolder();
		mSurfaceHolder.addCallback(this);
		//在这里获取屏幕的宽高是为0的。在网上看到说是在这里布局还没有绘制出来获取到的宽高就为0。
//		Rect mRect=mSurfaceHolder.getSurfaceFrame();
//		mRect.width();
//		mRect.height();
	}
	
	public MyPinBallSurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		tableWidth=getWidth();
		tableHeight=getHeight();
		racketY=tableHeight-50;
		flag=true;
		start();
		mThread=new Thread(this);
		mThread.start();
	}

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

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		flag=false;
	}
    
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			x=event.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			break;
		case MotionEvent.ACTION_UP:
			//点击的位置在挡板的位置右侧则向左移
			if(x<=racketX){
				if(racketX>0){
					racketX-=10;
				}
			}
			//这里判断点击的位置在挡板的右边则向右移
			if(x>=(racketX+RACKET_WIDTH)){
				if(racketX<tableWidth-RACKET_WIDTH){
					racketX+=10;
				}
			}
			break;
		}
		return true;
	}
	
	
	@Override
	public void run() {
	   while(flag){
		   myDraw();
	   }
	}
	
	public void start(){
		final Timer mTimer=new Timer();
		mTimer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				//如果小球碰到左边边框  
	            if(ballX <= 0 || ballX >= tableWidth - BALL_SIZE){  
	                xSpeed = -xSpeed;  
	            }  
	            //如果小球高度超出了球拍位置,且横向不在球拍范围之内,游戏结束  
	            if(ballY >= racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)){  
	                mTimer.cancel();  
	                //设置游戏是否结束的旗标为true  
	                isLose = true;  
	            }  
	            //如果小球位于球拍之内,且到达球拍位置,小球反弹  
	            else if(ballY <= 0 || (ballY > racketY - BALL_SIZE && ballX > racketX && ballX <= racketX + RACKET_WIDTH)){  
	                ySpeed = -ySpeed;  
	            }  
	            //小球坐标增加  
	            ballY += ySpeed;  
	            ballX += xSpeed;  
			}
		},0,700);
	}
    
	/**
	 * 游戏绘图自定义的绘图方法
	 */
	public void myDraw(){
		Canvas mCanvas=null;
		try{
			mCanvas=mSurfaceHolder.lockCanvas();
			if(mCanvas!=null){
				mCanvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);
				Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
				mPaint.setStyle(Paint.Style.FILL);
				if(isLose){
					mPaint.setColor(Color.RED);
					mCanvas.drawText("游戏结束!",150,200,mPaint);
				}else{
					  mPaint.setColor(Color.rgb(240, 240, 80));
					  mCanvas.drawCircle(ballX,ballY,BALL_SIZE,mPaint);
					  //设置颜色,并绘制挡板
		              mPaint.setColor(Color.rgb(80, 80, 200));
		              mCanvas.drawRect(racketX,racketY, racketX + RACKET_WIDTH,  
		                      racketY+RACKET_HEIGHT,mPaint);  
				}
			}
		}catch(Exception e){
		 e.printStackTrace();	
		}finally{
			if(mCanvas!=null){
				mSurfaceHolder.unlockCanvasAndPost(mCanvas);
			}
		}
		try {
			Thread.sleep(30);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

b.MainActivity类

  

protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(new MyPinBallSurfaceView(this));
}