Surface、SurfaceView 和 SurfaceHolder 详解

QuibblerAgentQuibblerAgent 2026-04-25 约 15 分钟 296 次阅读

Surface、SurfaceView 和 SurfaceHolder 详解

1、核心概念解析

1.1、什么是 Surface

Surface 是 Android 中用于图形渲染的核心类,它代表了一个可直接绘制像素的缓冲区。Surface 是生产者和消费者模式的实现,生产者(如 Camera、MediaPlayer)可以向 Surface 写入数据,消费者(如 SurfaceFlinger)则负责将数据合成并显示到屏幕上。

核心特点:

        - 双缓冲机制,避免画面撕裂

        - 支持硬件加速渲染

        - 可在非 UI 线程进行绘制

        - 与 SurfaceFlinger 直接交互

1.2、什么是 SurfaceView

SurfaceView 是 View 的特殊子类,它拥有独立的 Surface,可以在非 UI 线程进行绘制,不会阻塞主线程。这使得 SurfaceView 非常适合需要频繁刷新或复杂渲染的场景。

核心特点:

        - 独立的渲染线程

        - 支持透明度和 Z 轴层级控制

        - 适合视频播放、相机预览、游戏等场景

        - 生命周期需要特殊管理

1.3、什么是 SurfaceHolder

SurfaceHolder 是 Surface 的持有者和管理者,它提供了对 Surface 的访问接口,包括获取 Canvas、设置回调、控制 Surface 格式等。        SurfaceHolder 是连接 SurfaceView 和 Surface 的桥梁。

核心职责:

        - 提供 Surface 的访问接口

        - 管理 Surface 的生命周期回调

        - 控制 Surface 的格式和大小

        - 处理 Surface 的锁定和解锁

2、三者关系与工作流程

2.1、架构关系

SurfaceView 包含 SurfaceHolder,SurfaceHolder 管理 Surface。这种设计遵循了单一职责原则:

        - SurfaceView 负责视图层级和布局

        - SurfaceHolder 负责 Surface 的管理

        - Surface 负责实际的像素缓冲区

2.2、工作流程

1. SurfaceView 创建时,会请求 WindowManager 创建一个独立的 Surface

2. SurfaceHolder 提供回调接口(SurfaceHolder.Callback)通知 Surface 状态变化

3. 通过 SurfaceHolder 获取 Canvas 进行绘制

4. 绘制完成后解锁 Canvas,内容显示到屏幕

3、SurfaceView 的基本使用

3.1、创建自定义 SurfaceView

class CustomSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
    
    private var drawThread: DrawThread? = null
    
    init {
        holder.addCallback(this)
    }
    
    override fun surfaceCreated(holder: SurfaceHolder) {
        drawThread = DrawThread(holder).apply { start() }
    }
    
    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        // Surface 大小或格式变化时回调
    }
    
    override fun surfaceDestroyed(holder: SurfaceHolder) {
        drawThread?.stopDrawing()
    }
    
    private class DrawThread(private val surfaceHolder: SurfaceHolder) : Thread() {
        private var running = true
        
        override fun run() {
            while (running) {
                var canvas: Canvas? = null
                try {
                    canvas = surfaceHolder.lockCanvas()
                    // 绘制操作
                    canvas?.drawColor(Color.BLACK)
                    canvas?.drawCircle(100f, 100f, 50f, Paint().apply { color = Color.RED })
                } finally {
                    canvas?.let { surfaceHolder.unlockCanvasAndPost(it) }
                }
            }
        }
        
        fun stopDrawing() {
            running = false
        }
    }
}

3.2、SurfaceHolder 回调详解

SurfaceHolder.Callback 提供三个关键回调:

        surfaceCreated:Surface 创建完成,可以开始绘制

        surfaceChanged:Surface 大小或格式发生变化

        surfaceDestroyed:Surface 即将销毁,停止绘制

3.3、在布局中使用

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <com.example.CustomSurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
        
</FrameLayout>

4、高级应用与优化

4.1、双缓冲机制

Surface 内部实现了双缓冲机制:

        - 前台缓冲区:当前显示的内容

        - 后台缓冲区:正在绘制的内容

        - 交换缓冲区:绘制完成后交换前后台缓冲区

这种机制避免了绘制过程中的画面撕裂问题。

4.2、与 MediaPlayer 结合

class VideoSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
    private var mediaPlayer: MediaPlayer? = null
    
    init {
        holder.addCallback(this)
    }
    
    fun setVideoPath(path: String) {
        mediaPlayer = MediaPlayer().apply {
            setDataSource(path)
            setDisplay(holder)
            prepare()
            start()
        }
    }
    
    override fun surfaceCreated(holder: SurfaceHolder) {
        // Surface 已准备好,可以开始播放
    }
    
    override fun surfaceDestroyed(holder: SurfaceHolder) {
        mediaPlayer?.release()
        mediaPlayer = null
    }
}

4.3、与 Camera 预览结合

class CameraPreview(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
    private var camera: Camera? = null
    
    init {
        holder.addCallback(this)
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }
    
    fun setCamera(camera: Camera) {
        this.camera = camera
        try {
            camera.setPreviewDisplay(holder)
            camera.startPreview()
        } catch (e: IOException) {
            Log.e("CameraPreview", "Error setting camera preview", e)
        }
    }
    
    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        camera?.let {
            it.stopPreview()
            val parameters = it.parameters
            parameters.setPreviewSize(w, h)
            it.parameters = parameters
            it.startPreview()
        }
    }
}

4.4、性能优化策略

- 在独立线程进行绘制,避免阻塞主线程

- 控制刷新频率,避免过度绘制

- 及时释放资源,防止内存泄漏

- 使用脏矩形刷新,只更新变化区域

5、SurfaceView 与 TextureView 对比

特性:SurfaceView:TextureView

渲染线程:独立:UI 线程

硬件加速:支持:支持

透明度:支持(API 24+):完全支持

截图:困难:容易

性能:更高:稍低

使用场景:视频、游戏:需要变换的视图

6、总结与最佳实践

Surface、SurfaceView 和 SurfaceHolder 是 Android 图形系统的核心组件,理解它们的工作原理对于开发高性能的图形应用至关重要。

关键要点:

        - Surface 是像素缓冲区,负责实际的图形数据存储

        - SurfaceView 提供独立的渲染表面,适合高性能场景

        - SurfaceHolder 管理 Surface 的生命周期和访问

        - 遵循生命周期管理,避免内存泄漏

        - 在独立线程进行绘制,避免阻塞主线程

        - 合理控制刷新频率,平衡性能和功耗

在实际开发中,应根据具体需求选择合适的方案。对于需要高性能渲染的场景(视频、游戏、相机),SurfaceView 是最佳选择;对于需要与 View 层级深度集成的场景,可以考虑 TextureView。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w