• 详解SurfaceView和TextureView


    SurfaceView和TextureView都继承View,与普通的View不同的是,它俩可以在独立线程中绘制渲染,性能更高,所以常被应用在对绘制速率要求比较高的场景,比如相机预览,视频播放等等。

    Surface

    官方对Surface的解释是:由屏幕合成器管理的原始缓冲区上的句柄,所谓原生缓冲器,是用于保存当前窗口的像素数据的,也就是说,通过Surface可以获取原生缓冲器以及其中的内容。Surface对应一块屏幕缓冲区,每个Window对应一个Surface,任何View都画在Surface上,Surface中的Canvas,是用于提供画图的地方。

    SurfaceView

    SurfaceView与普通的View不同,它拥有自己的Surface,它的工作方式是创建一个区别于应用窗口的新窗口,与宿主窗口分离,可以在单独线程中处理业务,不受View的属性控制,无法进行平移缩放等转换,它是通过“双缓冲”机制来达到高效的界面刷新效果。

    双缓冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上。双缓冲主要是为了解决反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来。

    下面通过一个相机预览的功能,来看一下SurfaceView的具体使用

        private lateinit var surfaceHolder: SurfaceHolder
    
    • 1

    获取摄像机管理类,打开某个具体的摄像机,在打开成功的回调里面,创建预览请求

            val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
    
            val surfaceView = findViewById<SurfaceView>(R.id.surfaceView)
            surfaceHolder = surfaceView.holder
            surfaceHolder.setKeepScreenOn(true)
            surfaceHolder.addCallback(object : SurfaceHolder.Callback {
                override fun surfaceCreated(p0: SurfaceHolder) {
                    if (ActivityCompat.checkSelfPermission(
                            this@SurfaceActivity,
                            Manifest.permission.CAMERA
                        ) != PackageManager.PERMISSION_GRANTED
                    ) {
                        //无相机权限
                        return
                    }
                    try {
                        //获取可用相机设备列表
                        val cameraIdList = cameraManager.cameraIdList
                        //打开相机
                        cameraManager.openCamera(
                            cameraIdList[0],
                            //摄像头创建监听
                            object : CameraDevice.StateCallback() {
                                override fun onOpened(p0: CameraDevice) { //打开摄像头
                                    try {
                                        startPreview(p0)
                                    } catch (e: CameraAccessException) {
                                        e.printStackTrace()
                                    }
                                }
    
                                override fun onDisconnected(p0: CameraDevice) { //关闭摄像头
                                    p0.close()
                                }
    
                                override fun onError(p0: CameraDevice, p1: Int) {
                                    Log.i(tag, "CameraDevice.StateCallback onError")
                                }
                            },
                            null
                        )
                    } catch (e: CameraAccessException) {
                        e.printStackTrace()
                    }
                }
    
                override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {
                    Log.i(tag, "surfaceChanged")
                }
    
                override fun surfaceDestroyed(p0: SurfaceHolder) {
                    Log.i(tag, "surfaceDestroyed")
                }
    
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    开始预览

        private fun startPreview(cameraDevice: CameraDevice) {
            val captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            captureRequest.addTarget(surfaceHolder.surface)
            cameraDevice.createCaptureSession(
                listOf(surfaceHolder.surface),
                //会话状态回调
                object : CameraCaptureSession.StateCallback() {
                    override fun onConfigured(p0: CameraCaptureSession) {
                        try {
                            // 创建预览需要的CaptureRequest.Builder
                            val previewRequestBuilder =
                                cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                            previewRequestBuilder.addTarget(surfaceHolder.surface)
                            val previewRequest = previewRequestBuilder.build()
                            p0.setRepeatingRequest(previewRequest, null, null)
                        } catch (e: CameraAccessException) {
                            e.printStackTrace()
                        }
                    }
    
                    override fun onConfigureFailed(p0: CameraCaptureSession) {
                        Log.i(tag, "onConfigureFailed")
                    }
    
                }, null
            )
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这样,简易的相机预览功能就出来啦,当然,我们还需要申请CAMERA权限,这里略去。

    TextureView

    TextureView可以说是一个结合了View和SurfaceTexture的View对象,一个可以把内容流作为外部纹理输出在上面的 View,它只能用于开启了硬件加速的窗口,TextureView不会创建一个独立的窗口,而是像普通的View一样,可以进行平移、旋转等动画,TextureView在Andriod 4.0之后的 API 中才能使用,不过现在的安卓设备基本不存在Andriod 4.0之前的版本了,所以这点不必在意。

    TextureView的使用也比较简单,需要获取到它的SurfaceTexture,然后就可以以此来渲染了,下面通过一个简易的视频播放的示例,来瞧瞧它是怎么使用的。

            val textureView = findViewById<TextureView>(R.id.textureView)
            val mediaPlayer = MediaPlayer()
            textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
                override fun onSurfaceTextureAvailable(p0: SurfaceTexture, p1: Int, p2: Int) {
                    with(mediaPlayer) {
                        setDataSource(GlobalData.videoUrl)
                        setSurface(Surface(p0))
                        prepare()
                        start()
                        Log.i(tag, "setOnPreparedListener")
                        setOnPreparedListener {
                            it.start()
                        }
                    }
                }
    
                override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture, p1: Int, p2: Int) {
    
                }
    
                override fun onSurfaceTextureDestroyed(p0: SurfaceTexture): Boolean {
                    mediaPlayer.stop()
                    mediaPlayer.release()
                    return true
                }
    
                override fun onSurfaceTextureUpdated(p0: SurfaceTexture) {
    
                }
    
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    SurfaceTexture

    SurfaceTexture是Surface和OpenGL ES纹理的组合,用于提供输出到OpenGL ES纹理的Surface,和SurfaceView不同的是,它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理,如Camera滤镜,桌面特效等,但是这样会有若干帧的延迟。同时,由于它本身管理BufferQueue,因此内存消耗也会稍微大一些。比如Camera的预览数据,变成纹理后就可以通过SurfaceTexture交给TextureView作为View层级中的一个硬件加速层来显示。

    SurfaceView和TextureView的区别

    • SurfaceView是直接输出的,拥有自己独立Surface,它的渲染可以放在单独线程,其缺点是不能做变形和动画。
    • TextureView是一个可以把内容流作为外部纹理输出的,本身必须是一个硬件加速层,显示画面更新时有1~3帧的延迟。
    • TextureView本身也包含了SurfaceTexture,它与SurfaceView+SurfaceTexture组合相比,也可以把内容流上的图像转成纹理输出,区别在于TextureView是在View层级中绘制的,而SurfaceView+SurfaceTexture在单独的Surface上做绘制的。
    SurfaceViewTextureView
    占用内存低占用内存高
    耗电低耗电高
    绘制及时1-3帧延时
    不支持动画截图支持动画截图

    个人觉得,对于需要不断更新画布的游戏来说,SurfaceView是最好的选择,对于视频播放器或相机应用的开发,则TextureView更加适合。

  • 相关阅读:
    [附源码]计算机毕业设计springboot停车场管理系统
    【AI视野·今日Robot 机器人论文速览 第四十七期】Wed, 4 Oct 2023
    读书感悟【Vue.js设计与实现】第1章 权衡的艺术 【Vue进阶系列】
    山西电力市场日前价格预测【2023-11-07】
    生物素标记甾体化合物/多杀菌素探针分子/壳聚糖/聚乙二醇偶连基团为华生物提供
    JVM面试
    Android学习笔记 57. 了解API级别和兼容性
    ES6——ES6内置对象
    带你玩转CompletableFuture异步编程
    卫星遥感·格物致知丨卫星遥感的力量——自然灾害监测的太空之眼—洪涝灾害监测
  • 原文地址:https://blog.csdn.net/qq_45485851/article/details/126367125