一、SurfaceView存在的意义:

        一般开发中,可能View已经可以满足需求了。View是通过刷新重绘视图,Android系统通过发出VSYNC信号来进行屏幕的重绘,刷新时间间隔为16ms。如果在16ms内View完成了所需执行的所有操作,屏幕就不会卡顿;但是如果View执行的逻辑操作太多,例如游戏界面需要频繁刷新,这时16ms内完不成这些操作,屏幕就会发生卡顿(因为View的操作阻塞了主线程)。在自定义View的Log中出现了:“Skipped 47 frames!The application may be doing to much work on its main thread”,就是因为在图形的绘制过程中处理了过多的逻辑。这时就需要将这些逻辑放在子线程中,就需要使用SurfaceView。

二、View和SurfaceView的区别:

       1、View主要适用于主动更新的情况下,SurfaceView主要适用于被动更新,例如频繁的刷新;

       2、View在主线程中对画面进行刷新,SurfaceView通过一个子线程实现对页面的刷新;

       3、View在绘图是没有使用双缓冲机制,SurfaceView在底层实现机制中就已经实现了双缓冲机制。

       总结:自定义的View需要频繁刷新或者刷新数据量过大时,就可以考虑使用SurfaceView了。

三、SurfaceView的使用:

        1、创建SurfaceView:继承SurfaceView并实现SurfaceHolder.Callback,Runnable:继承SurfaceView并实现SurfaceHolder.Callback,Runnable接口;

        2、初始化SurfaceView:自定义SurfaceView时通常需要三个变量:

//SurfaceHolder
	private SurfaceHolder mHolder;
	//用于绘图的Canvas
	private Canvas mCanvas;
	//子线程标志位,用来控制子线程
	private boolean mIsDrawing;



               初始化:

mHolder = getHolder();
	mHolder.addCallback(this);

          3、使用SurfaceView:通过SurfaceView的lockCanvas()方法获取当前的Canvas。注意:获取到的Canvas还是上次的Canvas,而不是一个新的对象,之前的绘图操作会被保留,如果不需要,可以使用drawColor()进行清屏操作。

               SurfaceView使用模板:

package com.mfc.view;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * 使用SurfaceView的模板
 * */
public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback,Runnable {

	//SurfaceHolder
	private SurfaceHolder mHolder;
	//用于绘图的Canvas
	private Canvas mCanvas;
	//子线程标志位
	private boolean mIsDrawing;
	public SurfaceViewTemplate(Context context) {
		super(context);
		initView();
	}

	public SurfaceViewTemplate(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}
	
	public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView();
	}
	
	public void initView(){
                //初始化操作
               mHolder = getHolder();
		mHolder.addCallback(this);
		setFocusable(true);
		setFocusableInTouchMode(true);
		this.setKeepScreenOn(true);
	}
	
	@Override
	public void run() {
		while (mIsDrawing) {
			draw();
		}
	}

	private void draw(){
		try {
			//获取画布
			mCanvas = mHolder.lockCanvas();
			//下面就可以开始画View了
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//将提交画布的代码写在finally里面,保证每次都能将内容提交
			if(mCanvas != null){
				mHolder.unlockCanvasAndPost(mCanvas);
			}
		}
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		mIsDrawing = true;
		new Thread(this).start();
		
	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) {
		mIsDrawing = false;
		
	}

}



四、SurfaceView使用实例:

1、绘制正弦图像:

绘制图形跟View基本相同:

主要代码:

package com.mfc.view;

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

public class SinView extends SurfaceView implements Callback, Runnable {
	// SurfaceHolder
	private SurfaceHolder mHolder;
	// 用于绘图的Canvas
	private Canvas mCanvas;
	// 子线程标志位
	private boolean mIsDrawing;
	
	private Paint paint;
	private Path path;
	private int x = 0;
	private int y = 0;

	public SinView(Context context) {
		super(context);
		initView();
	}

	public SinView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}

	public SinView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView();
	}

	public void initView() {
		mHolder = getHolder();
		mHolder.addCallback(this);
		setFocusable(true);
		setFocusableInTouchMode(true);
		this.setKeepScreenOn(true);
		paint = new Paint();
		path = new Path();
		//起点坐标
		path.moveTo(0, 200);
	}

	@Override
	public void run() {
		while (mIsDrawing) {
			draw();
			x = x+1;
			y = (int) (100 * Math.sin(x * 2 * Math.PI / 180 )+400);
			path.lineTo(x, y);
		}
	}

	private void draw() {
		try {
			// 获取画布
			mCanvas = mHolder.lockCanvas();
			// 下面就可以开始画View了
			mCanvas.drawColor(Color.WHITE);
			paint.setStyle(Style.STROKE);
			//绘制路径
			mCanvas.drawPath(path, paint);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 将提交画布的代码写在finally里面,保证每次都能将内容提交
			if (mCanvas != null) {
				mHolder.unlockCanvasAndPost(mCanvas);
			}
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		mIsDrawing = true;
		new Thread(this).start();

	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) {
		mIsDrawing = false;

	}

}



效果图:

android 优化surfaceView绘制速度 surfaceview刷新_android


2、绘图板:

主要代码:

package com.mfc.view;

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

public class MyView extends SurfaceView implements Callback, Runnable {
	// SurfaceHolder
	private SurfaceHolder mHolder;
	// 用于绘图的Canvas
	private Canvas mCanvas;
	// 子线程标志位
	private boolean mIsDrawing;
	
	private Paint paint;
	private Path path;

	public MyView(Context context) {
		super(context);
		initView();
	}

	public MyView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}

	public MyView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView();
	}

	public void initView() {
		mHolder = getHolder();
		mHolder.addCallback(this);
		setFocusable(true);
		setFocusableInTouchMode(true);
		this.setKeepScreenOn(true);
		paint = new Paint();
		path = new Path();
		//起点坐标
		path.moveTo(0, 200);
	}

	@Override
	public void run() {
		//在子线程中进行sleep,让绘图板不会一直不断地更新,用来节省系统资源
		long start = System.currentTimeMillis();
		while (mIsDrawing) {
			draw();
		}
		long end = System.currentTimeMillis();
		if(end - start <100){
			try {
				Thread.sleep(100-(end - start));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void draw() {
		try {
			// 获取画布
			mCanvas = mHolder.lockCanvas();
			// 下面就可以开始画View了
			mCanvas.drawColor(Color.WHITE);
			paint.setStyle(Style.STROKE);
			paint.setStrokeWidth(10);
			mCanvas.drawPath(path, paint);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 将提交画布的代码写在finally里面,保证每次都能将内容提交
			if (mCanvas != null) {
				mHolder.unlockCanvasAndPost(mCanvas);
			}
		}
	}
	
	//记录手指划过的路径
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int x = (int) event.getX();
		int y = (int) event.getY();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			//手指按下点坐标
			path.moveTo(x, y);
			break;
		case MotionEvent.ACTION_MOVE:
			//手指移动到的位置坐标
			path.lineTo(x, y);
			break;
		case MotionEvent.ACTION_UP:
			//手指松开
			break;
		}
		return true;
	}

	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		mIsDrawing = true;
		new Thread(this).start();

	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) {
		mIsDrawing = false;

	}

}



效果图:

android 优化surfaceView绘制速度 surfaceview刷新_android_02


源码下载: