Hi,欢迎来到华清远见移动互联网学院官网!国内王牌JAVAEE培训、Android培训、HTML5培训、UI培训、JAVA培训、VR培训机构!

  • 400-611-6270
  • 新浪微博
  • 微信
您当前的位置:移动互联网学院 > Android开发 > SurfaceView绘图

SurfaceView绘图

时间:2017-06-15 09:09 来源:移动互联网学院

通常情况下的UI绘制和响应都是在Android的主线程中进行,比如Button、TextView等控件,但是这些动作都是非常轻量级的。有时候可能需要大量的绘图动作,这个时候仍然在主线程中去执行可能就会阻塞造成ANR现象的出现。那么如何在子线程中进行绘制呢?这个时候就需要用到SurfaceView来避免上述情况的发生。

SurfaceView拥有独立于主窗口的绘制图层,并且可以在子线程中进行大量的图像图形绘制,比如一些游戏、视频播放和拍照都是基于SurfaceView的这种机制上去实现的,从而避免主线程因为这些耗时操作造成不必要的各种麻烦。

简单来说实现SurfaceView需要继承SurfaceView类并实现其操作类SurfaceHolder下的Callback接口。

继承SurfaceView需要实现的方法如下:

(1) public void surfaceCreated(SurfaceHolder holder)

SurfaceView创建时的回调方法。

(2) public void surfaceChanged(SurfaceHolder holder,int format,int width,int height)

SurfaceView改变时的回调方法。

(3) public void surfaceDestroyed(SurfaceHolder holder)

SurfaceView销毁时的回调方法。

SurfaceHolder必须要实现addCallback(SurfaceHolder.Callback callback)方法,给操作类一个回调对象。

完成上述框架后,一个SurfaceView的框架就搭建好了,最后只要在相关的回调中开启子线程进行相应的UI绘制即可。

下面一个例子,来介绍具体的使用方法。

首先是自定义的SurfaceView的子类MySurfaceView:

public class MySurfaceView extends SurfaceView

        implements SurfaceHolder.Callback {

    private SurfaceHolder mHolder;

    private RefreshViewThread mThread;

    public MySurfaceView(Context context) {

        super(context);

        mHolder = getHolder();

        mHolder.addCallback(this);

        //建立一个绘制UI的子线程,将SurfaceView的操作类SurfaceHolder的对象作为参数传入。

        mThread = new RefreshViewThread(mHolder);

    }

    @Override

    public void surfaceCreated(SurfaceHolder holder) {

        //当创建SurfaceView后开启绘制UI的子线程

        mThread.start();

    }

    @Override

    public void surfaceChanged(SurfaceHolder holder, int format, int width,

            int height) {

    }

    @Override

    public void surfaceDestroyed(SurfaceHolder holder) {

        mThread.mFlag = false;

    }

}

下面是UI绘制的子线程实现类RefreshViewThread:

public class RefreshViewThread extends Thread {

    private SurfaceHolder mHolder;

    // 控制线程是否持续运行的标志位

    public boolean mFlag = false;

    private int mCount = 0;

    private Canvas mCanvas;

    public RefreshViewThread(SurfaceHolder holder) {

        mHolder = holder;

        mFlag = true;

    }

    @Override

    public void run() {

        try {

            while (mFlag) {

                // 锁定画布,返回一个Canvas对象,利用其可以进行绘制

                mCanvas = mHolder.lockCanvas();

                mCanvas.drawColor(Color.GRAY);

                Paint paint = new Paint();

                paint.setColor(Color.BLUE);

                // 在画布上绘制子线程绘制的次数

                mCanvas.drawText("Run times: " + mCount, 300, 300, paint);

                // 为了效果看的更显著,休眠一秒

                Thread.sleep(1000);

                // 当绘制完成后要释放画布,并且将上述绘制的效果提交

                mHolder.unlockCanvasAndPost(mCanvas);

                if (mCount < 5) {

                    mCount++;

                } else {

                    mFlag = false;

                    mCount = 0;

                    mCanvas = null;

                }

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

这样一个高效的SurfaceView通过子线程绘制UI的功能就实现了。尽管SurfaceView的性能优良,但是它只适合主动的绘制,即用户不进行操作屏幕依然在绘制的情况下,比如市面上的大多数动作游戏。有的场合下,只有用户进行触屏或者键盘输入后,UI才会有刷新绘制的过程,这种情况下还是使用View在主线程中绘制更节省手机的性能消耗。

  • 北京

    010-82600385/6

    北京市海淀区西三旗悦秀路北京明园大学校内

  • 上海

    021-54485127

    上海市徐汇区漕溪路250号银海大楼11层

  • 深圳

    0755-25590506

    深圳市龙华新区人民北路美丽AAA大厦15层

  • 成都

    028-85405115

    成都武侯区科华北路99号科华大厦2层

  • 南京

    025-86551900

    南京市白下区汉中路185号鸿运大厦11层

  • 武汉

    027-87804688

    武汉工程大学卓刀泉校区科技孵化器大楼11层

  • 西安

    029-88756251

    西安市高新区高新1路12号天公大厦3层

  • 广州

    020-38342087

    广州市天河软件园柯木塱园5栋三层

  • 沈阳

    024-24349000

    沈阳市沈河区北顺城路137号锦峰大厦7层

  • 济南

    0531-88898293

    济南市高新区舜华路三庆世纪财富中心B3座6层

  • 重庆

    023-68064704

    重庆市九龙坡区渝州路87号双薪时代九楼

  • 长沙

    15010390966

    长沙市开福区芙蓉中路海东青大厦B座11楼

Copyright © 2004-2017 华清远见教育集团 版权所有,沪ICP备10038863号-3,京公海网安备110108001117号