一般开发中,可能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。
1、View主要适用于主动更新的情况下,SurfaceView主要适用于被动更新,例如频繁的刷新;
2、View在主线程中对画面进行刷新,SurfaceView通过一个子线程实现对页面的刷新;
3、View在绘图是没有使用双缓冲机制,SurfaceView在底层实现机制中就已经实现了双缓冲机制。
总结:自定义的View需要频繁刷新或者刷新数据量过大时,就可以考虑使用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; } }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; } } 效果图:
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; } } 效果图:
源码下载:http://download.csdn.net/detail/fancheng614/9923626
