美文网首页
View之孪生兄弟——SurfaceView

View之孪生兄弟——SurfaceView

作者: 132xin | 来源:发表于2020-10-26 15:25 被阅读0次

    SurfaceView与View的区别

    如果在16ms内View完成了你所需要执行的所有操作,那么用户在视觉上,就不会产生卡顿的感觉;而如果操作的逻辑太多,特别是需要频繁刷新的界面商行,那么慢就不会不断阻塞主线程,从而导致画面卡顿。为了避免这一问题的产生,Android系统提供了SurfaceView组价来解决这个问题,SurfaceView可以说是View的孪生兄弟,但它与View还是有所不同的,它们的区别主要变现在以下几点。

    • View 主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁刷新。
    • View 在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面的刷新。
    • View 在绘图时没有使用缓冲机制,而SurfaceView的底层实现机制中就已经实现了双缓冲机制。

    SurfaceView的使用

    1.创建SurfaceView

    创建自定义的SurfaceView继承自SurfaceView,并实现两个接口——SurfaceHolder
    .Callback和Runnable,并重写相关的方法。其中SurfaceHolder.Callback的三个方法分别对应SurfaceView的创建,改变和销毁的过程。

    public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
        public MySurfaceView(Context context) {
            super(context);
        }
    
        public MySurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        @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() {
    
        }
    }
    
    
    2.初始化SurfaceView

    在自定义SurfaceView的构造方法中,需要对SurfaceView进行初始化。在自定义的SurfaceView中,通常需要定义以下三个成员变量:

       private SurfaceHolder mHolder;
        
        //画布,用于画图
        private Canvas mCanvas;
        
        //子线程标志位
        private  boolean mIsDrawing;
    

    初始化方法就是对SurfaceHolder进行初始化,通过以下代码来初始化一个SurfaceView对象,并注册SurfaceViewHolder的回调方法。

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

    另外两个成员变量——Canvas和标志位。对Canvas我们已经非常熟悉了,与在View的onDraw()方法中使用Canvas绘图一样,在SurfaceView中,我们也使用Canvas进行绘图,另一个标志位,则是用来控制子线程,SurfaceView通常会挂起一个子线程来进行绘制,而这个标志位就是可以控制子线程。

    3.使用SurfaceView

    通过SurfaceHolder对象的lockCanvas()方法,就可以获得当前的Canvas绘图对象。接下来,就可以在View中进行的绘制操作一下进行绘制了。不过需要注意的是,在获取到的Canvas对象还是继续上次的Canvas对象,而不是一个新的对象。因此,之前的绘图操作都是将保留,如果需要擦除,则可以在绘制前,通过drawColor()方法进行清屏的操作。
    绘制的时候,充分利用SurfaceView的三个回调方法,在surfaceCreate()方法中个开启子线程进行绘制,而子线程使用一个while(mIsDrawing)的循环来不停地进行绘制,在绘制的具体逻辑中,通过lockCanvas()方法获得的Canvas对象进行绘制,并通过unlockCanvasAndPost(mCanvas)方法对画布内容进行提交。

    public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
    
        private SurfaceHolder mHolder;
    
        //画布,用于画图
        private Canvas mCanvas;
    
        //子线程标志位
        private  boolean mIsDrawing;
    
        public MySurfaceView(Context context) {
            this(context,null);
        }
    
        public MySurfaceView(Context context, AttributeSet attrs) {
            this(context, attrs,0);
    
        }
    
        public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            this(context, attrs, defStyleAttr,0);
        }
    
        public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            intView();
        }
    
        private void intView() {
            mHolder=getHolder();
            mHolder.addCallback(this);
            setFocusable(true);
            setFocusableInTouchMode(true);
            this.setKeepScreenOn(true);
        }
    
    
        @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){
                draw();
            }
        }
    
        private void draw() {
            try {
                mCanvas=mHolder.lockCanvas();
                //进行绘制
            }catch (Exception e){
                
            }finally {
                if (mCanvas!=null){
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    }
    
    

    以上的代码基本上可以满足大部分的SurfaceView绘制需求,唯一需要注意的是在绘制方法中,将mHolder.unlockCanvasAndPost(mCavas)方法放到finally代码中,来保证每次都能将内容提交。

    相关文章

      网友评论

          本文标题:View之孪生兄弟——SurfaceView

          本文链接:https://www.haomeiwen.com/subject/oauvpktx.html