纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

Android中SurfaceView和普通view Android中SurfaceView和普通view的区别及使用

lidongxiu0714   2021-06-24 我要评论
想了解Android中SurfaceView和普通view的区别及使用的相关内容吗lidongxiu0714在本文为您仔细讲解Android中SurfaceView和普通view的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Android,SurfaceView,普通view下面大家一起来学习吧

1 SurfaceView介绍

在这里插入图片描述

SurfaceView第一印象它是一个view因为它继承了View有两个直接子类GLSurfaceView,VideoView但根据SDK文档SurfaceView和普通的view又有较大区别

最显著的区别就是普通view和它的宿主窗口共享一个绘图表面(Surface)SurfaceView虽然也在View的树形结构中但是它有属于自己的绘图表面Surface 内部持有一个Canvas可以利用这个Canvas绘制

SurfaceView提供一个直接的绘图表面(Surface)嵌入到视图结构层次中你可以控制这个Surface的格式大小SurfaceView负责在屏幕上正确的摆放Surface简单说就是SurfaceView拥有自己的Surface它与宿主窗口是分离的
我们知道窗口中的view共享一个windowwindow又对应一个Surface所以窗口中的view共享一个Surface而SurfaceView拥有自己的SurfaceSurfaceView会创建一个置于应用窗口之后的新窗口SurfaceView相当于在Window上挖一个洞它就是显示在这个洞里其他的View是显示在Window上所以View可以显示在 SurfaceView之上也可以添加一些层在SurfaceView之上

SurfaceView的窗口刷新的时候不需要重绘应用程序的窗口而android普通窗口的视图绘制机制是一层一层的任何一个子元素或者是局部的刷新都会导致整个视图结构全部重绘一次

对于普通的viewAndroid中的窗口界面包括多个View组成的View Hierachy的树形结构只有最顶层的DecorView才对WMS可见这个DecorView在WMS中有一个对应的WindowState此时APP请求创建Surface时会在SurfaceFlinger内部建立对应的Layer而对于SurfaceView它自带一个Surface这个Surface在WMS有自己对应的WindowState在SurfaceFlinger中有自己对应的layerSurfaceView从APP端看它仍然在View hierachy结构中但在WMS和SurfaceFlinger中它与宿主窗口是分离的因此SurfaceView的Surface的渲染可以放到单独线程去做不会影响主线程对事件的响应但因为这个Surface不在View hierachy中它的显示也不受View的属性控制所以不能进行平移缩放等变换(对SurfaceView进行ScrollByScrollTo操作没有效果(还有透明度旋转)普通View进行平移操作内部内容会移动SurfaceView进行这些操作内部不会移动如果对包裹它的ViewGroup进行平移旋转等操作也无法达到我们想要的效果同时SurfaceView不能放在类似RecyclerView或ScrollView中一些View中的特性也无法使用

SurfaceView不支持平移缩放旋转等动画但是当我们利用SurfaceView测试这些不支持的动画时如果使用的是7.0 甚至更高版本的Android系统会发现SurfaceView也支持平移缩放的动画操作

View和SurfaceView的区别:

View适用主动更新SurfaceView 适用被动更新如频繁的刷新
View在UI线程更新在非UI线程更新会报错当在主线程更新view时如果耗时过长也会出错, SurfaceView在子线程刷新不会阻塞主线程适用于界面频繁更新、对帧率要求较高的情况
SurfaceView可以控制刷新频率
SurfaceView底层利用双缓存机制绘图时不会出现闪烁问题

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

2 SurfaceView 使用步骤

使用SurfaceView的步骤:

首先要继承SurfaceView实现SurfaceHolder.Callback接口

重写方法:

  • surfaceChanged:surface大小或格式发生变化时触发在surfaceCreated调用后该函数至少会被调用一次
  • surfaceCreated:Surface创建时触发一般在这个函数开启绘图线程(新的线程不要再这个线程中绘制Surface)
  • surfaceDestroyed:销毁时触发一般不可见时就会销毁

利用getHolder()获取SurfaceHolder对象调用SurfaceHolder.addCallback添加回调

SurfaceHolder.lockCanvas 获取Canvas对象并锁定画布调用Canvas绘图SurfaceHolder.unlockCanvasAndPost 结束锁定画布提交改变

3 SurfaceHolder

SurfaceView的双缓冲的机制非常消耗系统内存Android规定SurfaceView不可见时会立即销毁SurfaceView的SurfaceHolder以达到节约系统资源的目的所以需要利用SurfaceHolder的回调函数对SurfaceHolder进行维护
提供了三个回调函数让我们知道SurfaceHolder的创建、销毁或者改变
void surfaceDestroyed(SurfaceHolder holder):当SurfaceHolder被销毁的时候回调
void surfaceCreated(SurfaceHolder holder):当SurfaceHolder被创建的时候回调
void surfaceChange(SurfaceHolder holder):当SurfaceHolder的尺寸或格式发生变化的时候被回调

abstract Canvas lockCanvas():
获取一个Canvas对象并锁定得到的Canvas对象就是Surface中一个成员

** abstract Canvas lockCanvas(Rectdirty):**
仅仅锁定dirty所指定的矩形区域

abstract void unlockCanvasAndPost(Canvascanvas)
当改动Surface中的数据后释放同步锁并提交改变然后将新的数据进行展示同一时候Surface中相关数据会被丢失

public abstract void setType (int type):
设置Surface的类型高版本中setType这种方法已经被depreciated了系统会自动设置

  • SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
  • SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的
  • SurfaceSURFACE_TYPE_GPU:适用于GPU加速的Surface
  • SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包括原生数据Surface用到的数据由其它对象提供在Camera图像预览中就使用该类型的Surface有Camera负责提供给预览Surface数据生成图像更流畅

兼容性:
SurfaceView的兼容性
  Android4.0以下SurfaceView不会自动维护缓冲区播放视频时如果使用SurfaceView开发游戏应用就需要我们自己维护这个缓冲区了

// 4.0版本之下需要设置的属性
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

4 SurfaceView的简单使用

绘制圆形:

public class SurfaceViewDemo extends SurfaceView implements SurfaceHolder.Callback{
    private SurfaceHolder mSurfaceHolder;
    private Canvas mCanvas;
    private Paint paint;

    public SurfaceViewDemo(Context context) {
        this(context,null,0);
    }

    public SurfaceViewDemo(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SurfaceViewDemo(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        System.out.println("=========surfaceCreated========");
        new Thread(new Runnable() {
            @Override
            public void run() {
                draw();
            }
        }).start();
    }

    private void draw() {
        try {
            System.out.println("============draw========");
            mCanvas = mSurfaceHolder.lockCanvas();
            mCanvas.drawCircle(500,500,300,paint);
            mCanvas.drawCircle(100,100,20,paint);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null)
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        System.out.println("=========surfaceChanged========");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        System.out.println("=========surfaceDestroyed========");
    }
}

在这里插入图片描述

回调函数的调用:
首次进入:
=surfaceCreated
=surfaceChanged
====draw
点击Home键:
=surfaceDestroyed

再次回到原来页面:
=surfaceCreated
=surfaceChanged
====draw

所以当SurfaceView不可见时会销毁SurfaceHolder再次进入会重新调用surfaceCreated生成新的SurfaceHoldersurfaceChanged函数在surfaceCreated调用后该函数至少会被调用一次

SurfaceView播放视频不要忘记存储权限
mediaPlayer.setDisplay(getHolder());
视频资源为利用模拟器录制的mp4视频

public class SurfaceViewDemo2 extends SurfaceView implements SurfaceHolder.Callback{
    private SurfaceHolder mSurfaceHolder;
    private Canvas mCanvas;
    private Paint paint;
    private MediaPlayer mediaPlayer;

    public SurfaceViewDemo2(Context context) {
        this(context,null,0);
    }

    public SurfaceViewDemo2(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SurfaceViewDemo2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
        setZOrderOnTop(true);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        System.out.println("=========surfaceCreated========");
        new Thread(new Runnable() {
            @Override
            public void run() {
                //draw();
              play();
            }
        }).start();
    }

    private void draw() {

        try {
            System.out.println("============draw========");
            mCanvas = mSurfaceHolder.lockCanvas();
            mCanvas.drawCircle(500,500,300,paint);
            mCanvas.drawCircle(100,100,20,paint);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null)
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        System.out.println("=========surfaceChanged========");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        System.out.println("=========surfaceDestroyed========");
        if (mediaPlayer != null ){
            stop();
        }
    }


    protected void stop() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    protected void play() {
        String path = "/sdcard/DCIM/Camera/VID_20190110_102218.mp4";
        File file = new File(path);
        if (!file.exists()) {
            return;
        }
            try {
                mediaPlayer = new MediaPlayer();
                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                // 设置播放的视频源
                mediaPlayer.setDataSource(file.getAbsolutePath());
                // 设置显示视频的SurfaceHolder
                mediaPlayer.setDisplay(getHolder());

                mediaPlayer.prepareAsync();
                mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {

                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        mediaPlayer.start();
                    }
                });
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        replay();
                    }
                });

                mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

                    @Override
                    public boolean onError(MediaPlayer mp, int what, int extra) {
                        play();
                        return false;
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
    }

    protected void replay() {
        if (mediaPlayer!=null){
         mediaPlayer.start();
        }else{
            play();
        }
    }

    protected void pause() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }else{
            mediaPlayer.start();
        }
    }
}

图片7

补充 对SurfaceView进行平移旋转等操作

添加 mSurfaceView.scrollBy(10,10);
效果如下:完全没有效果

在这里插入图片描述

对包裹它的viewgroup添加缩放动画

mContainer.animate().scaleX(0.4f).scaleY(0.7f);

在这里插入图片描述

此时拍摄出来的照片为:

在这里插入图片描述

拍摄出来的照片完全没有受缩放的影响


相关文章

猜您喜欢

网友评论

Copyright 2020 www.gamerfx.net 【游戏天空】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式