View孪生兄弟——SurfaceView

一、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;
}
}效果图:

View孪生兄弟——SurfaceView - 阿里云

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;
}
}效果图:

View孪生兄弟——SurfaceView - 阿里云

源码下载:http://download.csdn.net/detail/fancheng614/9923626