返回顶部
首页 > 资讯 > 移动开发 >Android中SurfaceView和普通view的区别及使用
  • 414
分享到

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

2024-04-02 19:04:59 414人浏览 安东尼
摘要

目录1 SurfaceView介绍2 SurfaceView 使用步骤3 SurfaceHolder4 SurfaceView的简单使用1 SurfaceView介绍 Surfa

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共享一个window,window又对应一个Surface,所以窗口中的view共享一个Surface,而SurfaceView拥有自己的Surface。SurfaceView会创建一个置于应用窗口之后的新窗口,SurfaceView相当于在Window上挖一个洞,它就是显示在这个洞里,其他的View是显示在Window上,所以View可以显示在 SurfaceView之上,也可以添加一些层在SurfaceView之上。

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

对于普通的view,Android中的窗口界面包括多个View组成的View Hierachy的树形结构,只有最顶层的DecorView才对WMS可见,这个DecorView在WMS中有一个对应的windowstate,此时APP请求创建Surface时,会在SurfaceFlinger内部建立对应的Layer。而对于SurfaceView它自带一个Surface,这个Surface在WMS有自己对应的WindowState,在SurfaceFlinger中有自己对应的layer。SurfaceView从APP端看它仍然在View hierachy结构中,但在WMS和SurfaceFlinger中它与宿主窗口是分离的。因此SurfaceView的Surface的渲染可以放到单独线程去做,不会影响主线程对事件的响应。但因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换(对SurfaceView进行ScrollBy,ScrollTo操作没有效果(还有透明度,旋转),普通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生成新的SurfaceHolder。surfaceChanged函数在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);

在这里插入图片描述

此时拍摄出来的照片为:

在这里插入图片描述

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

到此这篇关于Android中SurfaceView和普通view的区别及使用的文章就介绍到这了,更多相关Android中SurfaceView和普通view内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Android中SurfaceView和普通view的区别及使用

本文链接: https://lsjlt.com/news/129080.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android中SurfaceView和普通view的区别及使用
    目录1 SurfaceView介绍2 SurfaceView 使用步骤3 SurfaceHolder4 SurfaceView的简单使用1 SurfaceView介绍 Surfa...
    99+
    2024-04-02
  • Android系统view与SurfaceView的基本使用及区别分析
    目录一、引入:二、SurfaceView和View的不同之处三、SurfaceView的基本使用四、tips:解决方法一、引入: Android提供了View来进行绘图处理,在大部分...
    99+
    2024-04-02
  • Android中SurfaceTexture TextureView SurfaceView GLSurfaceView的区别
    目录SurfaceViewGLSurfaceViewSurfaceTextureTextureView实例解读SurfaceView, GLSurfaceView, SurfaceT...
    99+
    2024-04-02
  • Oracle中Materialized View与普通视图有什么区别
    存储方式不同:普通视图只是一个命名的查询结果集,不存储数据,每次查询都会重新执行查询语句;而Materialized View会...
    99+
    2024-04-19
    Oracle
  • Android Studio3.6中的View Binding初探及用法区别
    参考翻译:https://developer.android.google.cn/topic/libraries/view-binding View Binding是一项功能,...
    99+
    2022-06-07
    Android Studio studio view Android
  • android中Invalidate和postInvalidate的更新view区别
    Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。 An...
    99+
    2022-06-06
    view Android
  • Android中TextureView和SurfaceView怎么使用
    在Android中,TextureView和SurfaceView都是用于显示图形或视频的视图组件。它们的使用方式略有不同:1. 使...
    99+
    2023-09-29
    Android
  • Android中invalidate()和postInvalidate() 的区别及使用方法
    Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。 &n...
    99+
    2022-06-06
    方法 Android
  • 物化视图和普通视图的区别
        物化视图是一种特殊的物理表,“物化”(Materialized)视图是相对普通视图而言的。普通视图是虚拟表,应用的局限性大,任何对视图的查询,Oracle都实际上转换为视图SQL...
    99+
    2024-04-02
  • c++ 内联函数和普通函数的区别
    前言 内联函数是c++为了提高程序的运行速度做的改进,它与普通函数区别在于: 编译器如何将它们组合到程序中。所以我们需要深入到程序内部。 我们的最终的可执行程序由 一组机器指令组成...
    99+
    2024-04-02
  • mysql联合索引和普通索引的区别
            MySQL中,联合索引和普通索引都是用于加速查询的索引类型。它们之间的区别在于索引的列数和列的顺序。         普通索引只对单个列进行索引,而联合索引则同时对多个列进行索引,这些列可以按照特定的顺序组合在一起。例如,可...
    99+
    2023-09-07
    mysql 数据库 java
  • 普通服务器和云服务器的区别
    普通服务器和云服务器之间有很大的区别,以下是它们的主要区别:数据处理:普通服务器仅处理和存储大规模数据,如JSON数据,而云服务器则提供了更强大的处理和存储功能,例如数据库、消息队列等。性能:普通服务器在处理大规模的数据时通常速度较慢,而且...
    99+
    2023-10-26
    服务器 区别
  • 在java中普通类和抽象类有哪些区别
    java中普通类和抽象类的区别:普通类不能包含抽象方法,抽象类可以包含抽象方法。抽象类不能直接实例化,普通类可以直接实例化。抽象类可以有构造函数,抽象方法不能被声明为静态。抽象方法只需声明,而无需实现,抽象类中可以允许普通方法有主体。含有抽...
    99+
    2024-04-02
  • 云服务器显卡和普通显卡的区别
    云服务器显卡和普通显卡有一些区别,下面是一些主要的区别: 显卡核心数量:云服务器通常拥有多个CPU或GPU核心,而普通显卡通常只有一个显卡核心。在某些情况下,云服务器可能需要多台计算机或服务器同时处理多个任务。 显示芯片:云服务器通常使...
    99+
    2023-10-26
    显卡 区别 服务器
  • C++中new和malloc的区别及使用
    本篇内容介绍了“C++中new和malloc的区别及使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!定义上:malloc memory a...
    99+
    2023-06-04
  • es6中箭头函数和普通函数的区别有哪些
    这篇文章主要介绍es6中箭头函数和普通函数的区别有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 区别:1、箭头函数的定义要比普通函数定义简洁、清晰得...
    99+
    2024-04-02
  • php中静态变量和普通变量有什么区别
    本教程操作环境:windows7系统、PHP7.1版、DELL G3电脑在变量的前面加上static 就构成了静态变量(static 变量)。static变量和普通变量的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组...
    99+
    2014-09-28
    php 静态变量 普通变量
  • php中静态变量和普通变量有哪些区别
    这篇“php中静态变量和普通变量有哪些区别”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“php中静态变量和普通变量有哪些区别...
    99+
    2023-06-29
  • MySQL 普通索引和唯一索引的区别详解
    1 概念区分 普通索引和唯一索引 普通索引可重复,唯一索引和主键一样不能重复。 唯一索引可作为数据的一个合法验证手段,例如学生表的身份证号码字段,我们人为规定该字段不得重复,那么就使用唯一索引。(一般...
    99+
    2022-05-25
    MySQL 普通索引 MySQL 唯一索引
  • 普通服务器和云服务器的区别在哪
    普通服务器和云服务器之间有很大的区别,以下是它们的主要区别: 数据处理:普通服务器是一台计算机系统,通常包括内存、硬盘和存储设备。而云服务器是一种通过互联网连接的服务器,它们具有更大的存储空间和计算能力,可以处理大量数据。 资源分配:传...
    99+
    2023-10-26
    服务器 区别
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作