SurfaceView 与 TextureView 完全解析
视频播放与相机预览的最佳选择
目录
- View 家族对比
- SurfaceView 原理与使用
- TextureView 原理与使用
- 性能对比
- 选择指南
1. View 家族对比
View 渲染模式
flowchart TB
subgraph V["普通 View (View)"]
V1["渲染方式: 软件渲染 / 硬件渲染"]
V2["绘制: 主线程 Canvas.draw()"]
V3["层级: 在 View 层级中"]
V4["16ms 限制: 必须在 16ms 内完成"]
end
subgraph S["SurfaceView"]
S1["渲染方式: GPU 合成"]
S2["绘制: 子线程 SurfaceCanvas"]
S3["层级: 独立窗口,高于 View 层级"]
S4["特点: 可以在子线程绘制"]
end
subgraph T["TextureView"]
T1["渲染方式: 硬件加速"]
T2["绘制: 子线程 / SurfaceTexture"]
T3["层级: 在 View 层级中"]
T4["特点: 支持旋转、缩放、动画"]
end
2. SurfaceView 原理与使用
SurfaceView 原理
flowchart LR
Create["SurfaceView 创建"] --> C1["1. 创建独立 Surface(双缓冲)"]
Create --> C2["2. 创建独立 Canvas"]
Create --> C3["3. 在子线程中渲染"]
DrawThread["绘制线程"] --> Back["Back Buffer<br/>(后缓冲区)"]
Back --> Front["Front Buffer<br/>(前缓冲区)"]
Front --> Screen["显示设备 / 屏幕"]
Pros["优势"] --> P1["子线程渲染,不阻塞主线程"]
Pros --> P2["独立 Surface,双缓冲无闪烁"]
Pros --> P3["适合视频播放、相机预览、游戏"]
SurfaceView 使用
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 56 57 58 59 60
| class SurfaceViewDemo @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : SurfaceView(context, attrs), SurfaceHolder.Callback { private var drawThread: DrawThread? = null init { holder.addCallback(this) isFocusable = true } override fun surfaceCreated(holder: SurfaceHolder) { drawThread = DrawThread(holder).apply { start() } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { } override fun surfaceDestroyed(holder: SurfaceHolder) { drawThread?.running = false drawThread?.join() } inner class DrawThread(private val surfaceHolder: SurfaceHolder) : Thread() { var running = true override fun run() { while (running) { var canvas: Canvas? = null try { canvas = surfaceHolder.lockCanvas() synchronized(surfaceHolder) { drawFrame(canvas) } } finally { canvas?.let { surfaceHolder.unlockCanvasAndPost(it) } } } } private fun drawFrame(canvas: Canvas) { canvas.drawColor(Color.BLACK) } } }
|
相机预览示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class CameraPreview(context: Context) : SurfaceView(context), SurfaceHolder.Callback { private var camera: Camera? = null init { holder.addCallback(this) } override fun surfaceCreated(holder: SurfaceHolder) { camera = Camera.open().apply { setPreviewDisplay(holder) startPreview() } } override fun surfaceDestroyed(holder: SurfaceHolder) { camera?.apply { stopPreview() release() } camera = null } }
|
3. TextureView 原理与使用
TextureView 原理
flowchart LR
Texture["SurfaceTexture"] --> Buffer["Surface Buffer"]
Buffer --> GPU["GPU 合成"]
GPU --> ViewTree["TextureView<br/>(位于 View 树中)"]
Feature["TextureView 特性"] --> F1["需要硬件加速"]
Feature --> F2["参与普通 View 层级"]
Feature --> F3["支持旋转、缩放、透明度"]
Adv["优势"] --> A1["支持动画和变换"]
Adv --> A2["可以在主线程更新"]
Adv --> A3["占用内存少"]
Dis["劣势"] --> D1["需要硬件加速"]
Dis --> D2["不支持同时多个使用"]
TextureView 使用
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
| class TextureViewDemo @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : TextureView(context, attrs), SurfaceTextureListener { init { surfaceTextureListener = this } override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { startPreview() } override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) { } override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { return true } override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { } private fun startPreview() { } fun setRotation(degrees: Float) { rotation = degrees } fun setScale(scaleX: Float, scaleY: Float) { scaleX = scaleX scaleY = scaleY } }
|
视频播放示例
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
| class VideoPlayerView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : TextureView(context, attrs), TextureView.SurfaceTextureListener { private var mediaPlayer: MediaPlayer? = null private var surfaceTexture: SurfaceTexture? = null init { surfaceTextureListener = this } fun setVideoPath(path: String) { try { mediaPlayer?.release() mediaPlayer = MediaPlayer().apply { setDataSource(path) setSurface(Surface(surfaceTexture)) setOnPreparedListener { mp -> mp.start() } prepareAsync() } } catch (e: IOException) { e.printStackTrace() } } override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { surfaceTexture = surface } override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { mediaPlayer?.release() return true } }
|
4. 性能对比
性能对比表
| 指标 |
SurfaceView |
TextureView |
| 渲染线程 |
子线程 |
子线程 |
| 双缓冲 |
✅ 原生 |
✅ SurfaceTexture |
| 硬件加速 |
✅ GPU 合成 |
✅ GPU 合成 |
| 变换支持 |
❌ 不支持 |
✅ 旋转/缩放 |
| 动画支持 |
❌ 效果差 |
✅ 流畅 |
| 内存占用 |
低 |
中 |
| 耗电 |
低 |
中 |
| 截图困难 |
✅ 困难 |
✅ 简单 |
渲染性能测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| SurfaceView: - 帧率: 稳定 60fps - CPU: 较低 (子线程渲染) - 延迟: 最低
TextureView: - 帧率: 稳定 60fps - CPU: 中等 (需要 GPU 合成) - 延迟: 略高
普通 View: - 帧率: 可能掉帧 - CPU: 高 (主线程渲染) - 延迟: 高
|
5. 选择指南
决策表
| 场景 |
推荐 |
原因 |
| 视频播放 |
SurfaceView |
低延迟、子线程渲染 |
| 相机预览 |
SurfaceView |
实时性要求高 |
| 视频通话 |
TextureView |
需要变换 |
| 游戏背景 |
SurfaceView |
高帧率需求 |
| 需要旋转/缩放动画 |
TextureView |
支持变换 |
| 需要截图 |
TextureView |
简单实现 |
代码示例
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
| class VideoSurfaceView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : SurfaceView(context, attrs), MediaPlayer.OnPreparedListener { private var mediaPlayer: MediaPlayer? = null fun play(url: String) { mediaPlayer = MediaPlayer().apply { setDataSource(url) setDisplay(holder) setOnPreparedListener(this@VideoSurfaceView) prepareAsync() } } override fun onPrepared(mp: MediaPlayer?) { mp?.start() } }
class VideoTextureView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : TextureView(context, attrs), TextureView.SurfaceTextureListener { private var mediaPlayer: MediaPlayer? = null fun play(url: String) { setRotation(90f) setScaleX(1.5f) } }
|
面试常问
| 问题 |
答案 |
| SurfaceView 为什么快? |
子线程渲染,不阻塞主线程 |
| TextureView 有什么优势? |
支持变换、动画 |
| 两者区别? |
SurfaceView 独立窗口,TextureView 在 View 树中 |
总结
flowchart TB
Choose["选择原则"] --> C1["高性能 / 低延迟 → SurfaceView"]
Choose --> C2["需要变换 / 动画 → TextureView"]
Choose --> C3["相机 / 视频播放 → SurfaceView"]
Choose --> C4["视频通话 → TextureView"]
相关文章: