«

Android开发:SurfaceView基本用法总结及开发问题分享

时间:2024-3-2 18:05     作者:韩俊     分类: Android


本文主要讲解如何使用SurfaceView,并不涉及原理讲解,旨在帮助大家快速上手SurfaceView开发。如需了解原理,可以移步:(谷歌)SurfaceView原理详解 或者:(百度)SurfaceView原理详解

转载请注明作者xiong_it和链接:http://blog.csdn.net/xiong_it/article/details/45935421,谢谢!


SurfaceView基本介绍


1、系统给SurfaceView提供了一个专门绘图的Surface,嵌入在了SurfaceView视图层中

2、Surface是保存画面数据的地方,它持有一个Canvas对象,也就是说Surface是画面绘制的地方

3、SurfaceHolder是Surface的管理者,可以控制Surface的格式和大小等


综上所述:画面在Surface中绘制完成,在SurfaceView中通过获得SurfaceHolder的对象,管理并展示Surface的数据内容。


SurfaceView和普通View的区别:

普通view需要在UI线程中更新UI,否则容易造成ANR

SurfaceView是在工作线程中绘制视图


SurfaceView基本用法


需要使用SurfaceView的场合:视频播放,摄像预览,游戏开发等。总之,SurfaceView适用于需要频繁更新UI的场合。


自定义SurfaceView的基本流程:

1、继承SurfaceView

2、重写SurfaceView的至少一个构造方法

3、利用getHolder()方法得到SurfaceHolder的引用对象

4、给SurfaceHolder对象添加实现SurfaceHolder.Callback的接口对象

5、重写Callback的三个方法:surfaceChanged,surfaceCreated,surfaceDestroyed

6、利用SurfaceHolder对象设置Surface的格式

7、利用SurfaceHolder对象设置Surface的类型(Api 11以上已废弃)

8、利用SurfaceHolder对象设置Surface的大小宽高(可选项)


SurfaceView示例代码如下:

// 第一步:继承SurfaceView
public class VideoView extends SurfaceView{

    private SurfaceCallback mSurfaceCallback;
    private SurfaceHolder mSurfaceHolder;
    private Canvas mCanvas;
    private Panit mPanit;

    // 第二步:重写构造方法
    public VideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 第三步:获得SurfaceHolder对象
        mSurfaceHolder = this.getSurfaceHolder();
        // 第四步:添加SurfaceHolder.Callback接口
        mSurfaceHolder().addCallback(mCallback);
        // 第六步:设置Surface格式
        //         参数:PixelFormat中定义的int值,详细参见PixelFormat.java
        mSurfaceHolder().setFormat(PixelFormat.RGBA_8888); 
        // 第七步:设置Surface类型
        //   参数:SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface 
        //     SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface 
        //     SURFACE_TYPE_GPU:适用于GPU加速的Surface 
        //     SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,
        //                    在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。               
        mSurfaceHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    /**
     * 第八步:设置Surface的大小宽高(可选)
     *
     * 用于外部设置Surface的宽高
     * @param videoWidth 设置Surface的宽 
     * @param videoWidth 设置Surface的高
     */
    public void setVideoLayout(int videoWidth, int videoHeight) {
        mSurfaceHolder().setFixedSize(videoWidth, videoHeight);
    }

    /**
     * 第五步:实现SurfaceHolder.Callback的接口
     * 重写Callback的三个方法:surfaceChanged,surfaceCreated,surfaceDestroyed
     */
    private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {

        /**
         * 在Surface格式和大小发生变化时会被立即调用,可以在这个方法中更新Surface
         *
         * @param holder 持有当前Surface的SurfaceHolder对象
         * @param format surface的新格式
         * @param width surface的新宽度
         * @param height surface的新高度
         */
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        }

        /**
         * 在Surface首次创建时被立即调用:获得焦点时。一般在这里开启画图的线程。
         * @param holder 持有当前Surface的SurfaceHolder对象
         */
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mPanit = new Panit();

            //绘制一个向右走的圆圈
            new Thread() {
                public void run (){
                    synchronized (mSurfaceHolder) {
                        //获得Surface的画布对象
                        mCanvas = mSurfaceHolder.lockCanvas();
                        for (int i; i < 500 ; i++) {
                            //绘制向右的圆圈
                            mCanvas.drawCircle(15, 100, 15, mPanit);
                            try {
                                sleep(500);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        //释放画布对象更新Surface
                        mSurfaceHolder.unlockAndPost(mCanvas);
                        }
                    }
            }.start();
        }

        /**
         * 在Surface被销毁时立即调用:失去焦点时。一般在这将画图的线程停止销毁
         * @param holder 持有当前Surface的SurfaceHolder对象
         */
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            //TODO
    };
}

SurfaceView开发问题分享


在此SurfaceView上无法成功绘图

首先,我们按照标准步骤自定义了SurfaceView,然后,在Surface创建时开启了一个线程来绘制一个自左向右走的圆。假如大家把代码运行起来的话,会发现SurfaceView无法绘制圆出来这是为什么呢?

因为在设置Surface类型时:

mSurfaceHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//表明该Surface不包含原生数据,Surface用到的数据由其他对象提供


使用 SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS 这种类型时是无法自定义绘图的,请注意!


setType还有另外三种类型分别是:

       SurfaceHolder.SURFACE_TYPE_NORMAL // 用RAM缓存原生数据的普通Surface 
        SurfaceHolder.SURFACE_TYPE_HARDWARE //适用于DMA(Direct memory access )引擎和硬件加速的Surface 
        SurfaceHolder.SURFACE_TYPE_GPU //适用于GPU加速的Surface 


使用此SurfaceView视频无法播放

当使用MediaPlayer播放视频时,我们需要把SurfaceHolder对象传递进去:

mMediaPlayer.setDisplay(mSurfaceHolder);


结果发现只能绘图(上面代码中的圆mCanvas.drawCircle()),无法正常播放视频,声音也没有。那我又需要既播放视频,又能在视频上绘制我想要的圆的轨迹,怎么办呢?

我的解决办法是重写一个SurfaceView,专门用来绘制圆的轨迹,也就是采用两层SurfaceView重叠的方式来实现我的需求。

此时出现第二个问题,两个重叠的SurfaceView会有一个被盖住。两层SurfaceView重叠被盖住怎么办?

将绘制圆圈轨迹的SurfaceView的Surface格式(背景)设置为透明即可:

mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);// 设置背景透明,这个至关重要,不然会盖住视频
此时,圆圈轨迹绘被绘制在视频上面,完美解决两层SurfaceView重叠时被盖住的问题

在此SurfaceView绘图出现重影/叠影/残影

在绘图过程,有时发现,绘制的圆圈轨迹呈现出一条线,也就是重影问题,这不是我想要的结果。SurfaceView绘制出现重影怎么办呢?

解决办法时在每次绘制前进行清理

synchronized (mSurfaceHolder) {
    /** 拿到当前画布 然后锁定 **/
    mCanvas = mSurfaceHolder.lockCanvas();

    // canvas 清除画布内容。
    mPaint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.CLEAR));
    mCanvas.drawPaint(mPaint);
    mPaint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_OVER));

    mCanvas.drawCircle(x, y, radius, mPaint);

     if (mCanvas != null) 
      /** 绘制结束后解锁显示在屏幕上 **/
      mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}

清理画布完美解决SurfaceView绘图重影/叠影/残影 问题。


好了,今天 SurfaceView基本用法总结及开发问题分享 就到这里,希望对大家有所帮助!文中观点如有失误,还请各位斧正,谢谢!

转载请注明作者xiong_it和链接:http://blog.csdn.net/xiong_it/article/details/45935421,谢谢!

标签: android

热门推荐