一. 概述

Android中提供了View进行绘图处理,View可以满足大部分的绘图需求,但是有时候,View却显得力不从心,所以Android提供了SurfaceView给Android开发者,以满足更多的绘图需求。下面就让我们一起来了解一下SurfaceView。

我们知道View是通过刷新来重绘视图,系统通过发出VSSYNC信号来进行屏幕的重绘,刷新的时间间隔是16ms,如果我们可以在16ms以内将绘制工作完成,则没有任何问题,如果我们绘制过程逻辑很复杂,并且我们的界面更新还非常频繁,这时候就会造成界面的卡顿,影响用户体验,为此Android提供了SurfaceView来解决这一问题。

View和SurfaceView的区别:
1 . View适用于主动更新的情况,而SurfaceView则适用于被动更新的情况,比如频繁刷新界面。
2 . View在主线程中对页面进行刷新,而SurfaceView则开启一个子线程来对页面进行刷新。
3 . View在绘图时没有实现双缓冲机制,SurfaceView在底层机制中就实现了双缓冲机制。

双缓冲技术是游戏开发中的一个重要的技术。当一个动画争先显示时,程序又在改变它,前面还没有显示完,程序又请求重新绘制,这样屏幕就会不停地闪烁。而双缓冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上。
双缓冲主要是为了解决 反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来。

二. 如何使用SurfaceView
1 . 创建SurfaceView

我们需要自定义一个类继承自SurfaceView,并且实现两个接口以及接口定义的方法,当然,与自定义View类似,还要重写三个构造函数。下面是代码:

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {    public SurfaceViewTemplate(Context context) {        this(context, null);    }    public SurfaceViewTemplate(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public void surfaceCreated(SurfaceHolder holder) {       //创建    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        //改变    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        //销毁    }    @Override    public void run() {        //子线程    }}

前面三个构造函数的写法和自定义View是相同的,接下来的三个方法分别在SurfaceView创建、改变、销毁的时候进行调用,最后的run()方法中写我们子线程中执行的绘图逻辑即可。

2 . 初始化SurfaceView

这一步我们主要是定义三个成员变量以备后面绘图时使用,然后初始化这三个成员变量并且注册对应的回调方法。代码如下:

private SurfaceHolder mSurfaceHolder;//绘图的Canvasprivate Canvas mCanvas;//子线程标志位private boolean mIsDrawing;/** * 初始化View */private void initView(){    mSurfaceHolder = getHolder();    //注册回调方法    mSurfaceHolder.addCallback(this);    //设置一些参数方便后面绘图    setFocusable(true);    setKeepScreenOn(true);    setFocusableInTouchMode(true);}public SurfaceViewSinFun(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    //在三个参数的构造方法中完成初始化操作    initView();}
3 . 使用SurfaceView

(1) 通过lockCanvas()方法获得Canvas对象
(2) 在子线程中使用Canvas对象进行绘制
(3) 使用unlockCanvasAndPost()方法将画布内容进行提交

注意: lockCanvas() 方法获得的Canvas对象仍然是上次绘制的对象,由于我们是不断进行绘制,但是每次得到的Canvas对象都是第一次创建的Canvas对象。

SurfaceView的绘制可以使用下面的模板代码来实现,唯一的不同就是绘制逻辑的不同,代码如下:

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {    private SurfaceHolder mSurfaceHolder;    //绘图的Canvas    private Canvas mCanvas;    //子线程标志位    private boolean mIsDrawing;    public SurfaceViewTemplate(Context context) {        this(context, null);    }    public SurfaceViewTemplate(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView();    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        mIsDrawing = true;        //开启子线程        new Thread(this).start();    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        mIsDrawing = false;    }    @Override    public void run() {        while (mIsDrawing){            drawSomething();        }    }    //绘图逻辑    private void drawSomething() {        try {            //获得canvas对象            mCanvas = mSurfaceHolder.lockCanvas();            //绘制背景            mCanvas.drawColor(Color.WHITE);            //绘图        }catch (Exception e){        }finally {            if (mCanvas != null){                //释放canvas对象并提交画布                mSurfaceHolder.unlockCanvasAndPost(mCanvas);            }        }    }    /**     * 初始化View     */    private void initView(){        mSurfaceHolder = getHolder();        mSurfaceHolder.addCallback(this);        setFocusable(true);        setKeepScreenOn(true);        setFocusableInTouchMode(true);    }}
三. 案例
绘制正弦曲线
public class SurfaceViewSinFun extends SurfaceView implements SurfaceHolder.Callback, Runnable {    private SurfaceHolder mSurfaceHolder;    //绘图的Canvas    private Canvas mCanvas;    //子线程标志位    private boolean mIsDrawing;    private int x = 0, y = 0;    private Paint mPaint;    private Path mPath;    public SurfaceViewSinFun(Context context) {        this(context, null);    }    public SurfaceViewSinFun(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SurfaceViewSinFun(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mPaint = new Paint();        mPaint.setColor(Color.BLACK);        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setAntiAlias(true);        mPaint.setStrokeWidth(5);        mPath = new Path();        //路径起始点(0, 100)        mPath.moveTo(0, 100);        initView();    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        mIsDrawing = true;        new Thread(this).start();    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        mIsDrawing = false;    }    @Override    public void run() {        while (mIsDrawing){            drawSomething();            x += 1;            y = (int)(100 * Math.sin(2 * x * Math.PI / 180) + 400);            //加入新的坐标点            mPath.lineTo(x, y);        }    }    private void drawSomething() {        try {            //获得canvas对象            mCanvas = mSurfaceHolder.lockCanvas();            //绘制背景            mCanvas.drawColor(Color.WHITE);            //绘制路径            mCanvas.drawPath(mPath, mPaint);        } catch (Exception e){        } finally {            if ( mCanvas != null ) {                //释放canvas对象并提交画布                mSurfaceHolder.unlockCanvasAndPost(mCanvas);            }        }    }    /**     * 初始化View     */    private void initView(){        mSurfaceHolder = getHolder();        mSurfaceHolder.addCallback(this);        setFocusable(true);        setKeepScreenOn(true);        setFocusableInTouchMode(true);    }}

更多相关文章

  1. Android(安卓)性能分析工具之 TraceView 使用说明
  2. Android性能优化《Android开发艺术探索》笔记
  3. Android中引入第三方Jar包的方法(java.lang.NoClassDefFoundErro
  4. Android之Service案例-电话窃听
  5. Android(安卓)组件系列之Activity的传值和回传值
  6. Android(安卓)- toolbar 优化 title修改边距和navigation icon修
  7. Android(安卓)程序完全退出的几种方法(参考)
  8. Looper类浅析
  9. android上拔出sd卡导致flash上媒体也消失问题解决方法

随机推荐

  1. 巧用apache httpcore-nio实现android推送
  2. Galaxy Nexus 加个气压计来干什么呢?Googl
  3. Android(安卓)支持表情功能
  4. Android(安卓)BLE与终端通信(二)——Androi
  5. Android(安卓)使用AsyncTask 后监听异步
  6. Android用户界面之notifaction(状态栏通知
  7. Android中Dialog对话框的调用及监听
  8. 在Android(安卓)studio里面使用AIDL
  9. 安卓自动化测试-脚本相关初探
  10. 戒骄戒躁