Android SurfaceView与TextureView使用方法详细讲解

Surface

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

SurfaceView

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

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

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

private lateinit var surfaceHolder: SurfaceHolder

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

        val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
        val surfaceView = findViewById(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")
            }
        })

开始预览

    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
        )
    }

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

TextureView

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

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

        val textureView = findViewById(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) {
            }
        }

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上做绘制的。
SurfaceView TextureView
占用内存低 占用内存高
耗电低 耗电高
绘制及时 1-3帧延时
不支持动画截图 支持动画截图

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

到此这篇关于Android SurfaceView与TextureView使用方法详细讲解的文章就介绍到这了,更多相关Android SurfaceView与TextureView内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(Android SurfaceView与TextureView使用方法详细讲解)