SurfaceView、TextureView、SurfaceTexture 和 GLSurfaceView

Android图形渲染组件对比与选择

在 Android 中,SurfaceViewTextureViewSurfaceTextureGLSurfaceView 是与图形渲染和视频播放密切相关的核心类,它们各自有不同的特性和适用场景。下面详细对比它们的区别和用途:


1. SurfaceView

特点

  • 独立的绘图表面SurfaceView 拥有独立的 Surface(由 SurfaceFlinger 直接管理),与主窗口分离,不依赖主线程 UI 渲染
  • 双缓冲机制:减少画面撕裂(Tearing)。
  • 高效渲染:适用于视频播放、相机预览、游戏等高性能场景。
  • 层级限制:由于是独立 Surface,可能会被其他视图遮挡(需通过 setZOrderOnTopsetZOrderMediaOverlay 调整层级)。

生命周期

  • Surface 的创建和销毁通过 SurfaceHolder.Callback 监听:
    surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) { /* Surface 可用 */ }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { /* Surface 尺寸变化 */ }
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) { /* Surface 销毁 */ }
    });
    

适用场景

  • 视频播放(MediaPlayerExoPlayer
  • 相机预览(Camera2 API)
  • 高性能游戏(如 OpenGL ES 渲染)

2. TextureView

特点

  • 基于 SurfaceTexture:在 View 系统内渲染,支持动画、变换(平移、旋转、缩放)和透明度
  • 依赖主线程:通过 HardwareLayer 合成,性能略低于 SurfaceView
  • 无层级问题:作为普通 View,可以和其他视图自由叠加。

生命周期

  • 通过 SurfaceTextureListener 监听:
    textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { /* 可用 */ }
        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { /* 尺寸变化 */ }
        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { /* 销毁 */ return true; }
        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) { /* 内容更新 */ }
    });
    

适用场景

  • 需要动态变换(如视频播放 + 动画)
  • 与其他视图混合渲染(如叠加 UI 控件)

3. SurfaceTexture

特点

  • 不直接显示:仅提供图像数据流(BufferQueue 的生产者端),需要配合 TextureViewSurfaceView 渲染。
  • 离屏渲染:从 CameraMediaCodec 等获取图像流,处理后输出到 Surface
  • 低延迟:适用于相机滤镜、视频帧处理等场景。

基本用法

// 创建 SurfaceTexture 并监听帧更新
SurfaceTexture surfaceTexture = new SurfaceTexture(textureId);
surfaceTexture.setOnFrameAvailableListener(surface -> { /* 新帧可用时回调 */ });

// 将 SurfaceTexture 包装成 Surface,供相机/解码器使用
Surface surface = new Surface(surfaceTexture);
camera.setPreviewSurface(surface);

适用场景

  • 相机实时滤镜(如美颜)
  • 视频帧处理(如 OpenGL ES 后期处理)

4. GLSurfaceView

特点

  • 封装 OpenGL ES 渲染:继承自 SurfaceView,内置 EGL 管理、渲染线程和 GLSurfaceView.Renderer 接口。
  • 简化 OpenGL 开发:自动处理 Surface 生命周期和渲染循环。
  • 高性能图形:适用于 3D 图形、游戏、图像处理。

基本用法

glSurfaceView.setRenderer(new GLSurfaceView.Renderer() {
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) { /* OpenGL 初始化 */ }
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) { /* 视图尺寸变化 */ }
    @Override
    public void onDrawFrame(GL10 gl) { /* 逐帧渲染 */ }
});
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); // 连续渲染

适用场景

  • 3D 游戏(Unity/Unreal 底层)
  • 实时图像处理(如滤镜、特效)

对比总结

特性SurfaceViewTextureViewSurfaceTextureGLSurfaceView
渲染目标独立 Surface基于 View 系统离屏 BufferQueue独立 Surface + OpenGL
性能⭐⭐⭐⭐⭐(最高)⭐⭐⭐(依赖 UI 线程)⭐⭐⭐⭐(低延迟)⭐⭐⭐⭐⭐(GPU 加速)
动画/变换支持❌ 不支持✅ 支持❌ 需手动处理❌ 需 OpenGL 实现
层级问题可能被遮挡不直接显示类似 SurfaceView
适用场景视频/相机/游戏动态 UI + 视频帧处理/滤镜OpenGL ES 图形渲染

如何选择?

  1. 视频播放/相机预览SurfaceView(性能最优)。
  2. 视频 + UI 动画/变换TextureView
  3. 相机滤镜/帧处理SurfaceTexture + OpenGL ES
  4. 3D 图形/游戏GLSurfaceView(或直接使用游戏引擎)。

理解它们的差异,能帮助你在不同场景下选择最合适的组件!

### 使用 `SurfaceView` `SurfaceTexture` 进行视频渲染或摄像头预览 #### SurfaceViewSurfaceTexture关系概述 `SurfaceView` 是 Android 中用于显示多媒体内容的一个视图组件,它允许应用程序创建独立的窗口层来处理图形绘制操作。而 `SurfaceTexture` 则是自 Android 3.0 (API level 11) 起引入的一种特殊类型的 OpenGL ES 纹理对象,它可以接收来自相机或其他图像源的数据流并将其转换成纹理供 GPU 处理[^3]。 两者之间的主要区别在于: - **合成方式**: 当使用 `SurfaceView` 显示内容时,其背后的内容是由硬件合成器(即 SurfaceFlinger)负责管理并与其它应用界面元素一起组成最终的画面输出给屏幕;相比之下,当采用 `SurfaceTexture` 结合 `TextureView` 或者其他支持该特性的控件展示画面时,这些内容会先被传递至 GPU 并通过 OpenGL ES 渲染管线完成进一步加工后再参与整体 UI 绘制过程。 - **性能表现**: 如前所述,由于 `SurfaceView` 可以让媒体播放等任务绕过常规的应用程序绘图流程直接交给底层系统去执行,所以在某些情况下能够获得更好的性能优势特别是对于复杂场景下的实时性要求较高的场合而言更为明显。 #### 实现基于SurfaceViewSurfaceTexture的摄像机预览功能 下面给出一段简单的 Java 代码片段用来说明如何利用上述两个类实现基本的摄相头预览效果: ```java // 创建Camera实例 private Camera camera; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 获取SurfaceView引用 final SurfaceView surfaceView = findViewById(R.id.surface_view); final SurfaceHolder holder = surfaceView.getHolder(); holder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { try{ if(camera==null){ camera=Camera.open(); // 打开默认后置摄像头 } // 设置预览参数 Camera.Parameters parameters=camera.getParameters(); List<Size> previewSizes=parameters.getSupportedPreviewSizes(); Size optimalSize=getOptimalPreviewSize(previewSizes,holder.getSize().getWidth(),holder.getSize().getHeight()); parameters.setPreviewSize(optimalSize.width,optimalSize.height); camera.setParameters(parameters); // 将surface设置为camera预览目标 camera.setPreviewDisplay(holder); // 开始预览 camera.startPreview(); // 如果想要获取原始帧数据还可以注册callback监听 /* * camera.setPreviewCallback(new Camera.PreviewCallback(){ * @Override * public void onPreviewFrame(byte[] data,Camera camera){} * }); */ }catch(IOException e){ Log.e("MainActivity","Error setting up the camera",e); } } private Size getOptimalPreviewSize(List<Size> sizes,int w,int h){...}//省略具体算法 ... }); } @Override protected void onDestroy(){ super.onDestroy(); if(this.camera!=null){ this.camera.stopPreview(); this.camera.release(); this.camera=null; } } ``` 这段代码展示了怎样打开设备上的照相机并将捕捉到的画面呈现在界面上指定位置处所放置好的 `SurfaceView` 上面。需要注意的是这里并没有涉及到任何关于 `SurfaceTexture` 的部分——这是因为如果希望借助后者来进行更高级别的定制化开发工作的话,则需要额外构建一个继承自 `GLSurfaceView.Renderer` 接口的对象,并在里面定义好相应的着色器脚本以及顶点坐标数组等内容之后再调用 `setRenderer()` 方法传入即可[^2]。 另外值得注意的一点就是,在实际项目当中为了兼容更多版本号较低的操作系统环境建议优先考虑选用官方推荐的新一代 API —— 即 `android.hardware.Camera2` 替代旧版接口(`android.hardware.Camera`)进行编程实践。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值