25. Camera与SurfaceView:SurfaceView与TextureView对比、SurfaceView在Camera中的应用、性能考量

说到Android摄像头采集,SurfaceView和TextureView这两个家伙是绕不开的。我刚开始做Camera开发时,也在这两者之间纠结过很久。说白了,它们都是用来显示图像数据的,但底层机制和适用场景差别挺大。今天咱们就把它们掰开揉碎了聊一聊。

SurfaceView与TextureView:本质差异

先问一个问题:为什么Android要搞出两个View来显示摄像头画面?

答案其实很简单——性能与灵活性的取舍

SurfaceView的工作原理,是在WindowManager那里单独开一个图层。这个图层独立于View层级,有自己的Surface。你想想看,它不需要和普通View共享绘制流程,所以绘制效率极高。但代价是什么?它不能做动画、不能做平移缩放,连透明效果都很难搞。

TextureView就不一样了。它本质上是一个普通的View,内部持有一个Texture。它把图像数据当作纹理来处理,所以可以像操作普通View一样做各种变换。我在项目中遇到过需要给摄像头画面加圆角、做缩放动画的场景,TextureView就是首选。

来,看个对比表格会更清楚:

特性 SurfaceView TextureView
图层层级 独立图层(WindowManager) View层级内
绘制性能 高(直接操作Surface) 中等(需经过纹理合成)
动画/变换 不支持 完全支持
透明效果 难实现 原生支持
内存占用 较低 较高(纹理缓存)
适用场景 视频预览、游戏 UI特效、滤镜预览

核心结论:如果你只需要简单显示摄像头画面,没有花哨的UI需求,SurfaceView是更高效的选择。如果需要做特效、动画、圆角等,那就用TextureView。

SurfaceView在Camera中的应用

在实际的Camera开发中,SurfaceView的使用频率其实更高。为什么?因为大部分场景就是「打开摄像头→预览画面→拍照/录像」,不需要什么花哨的动画效果。

我记得有一次做扫码功能,产品经理要求扫码框周围半透明,中间全透明。嗯,这个用SurfaceView就有点麻烦了。但如果是普通的预览界面,SurfaceView完全够用,而且性能更好。

来看一个典型的SurfaceView配合Camera2的用法:

// 创建SurfaceView
SurfaceView surfaceView = new SurfaceView(context);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // Surface已创建,可以开始预览
        startCameraPreview(holder.getSurface());
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 尺寸变化时重新配置
        configureCamera(width, height);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 释放Camera资源
        closeCamera();
    }
});

// 在Camera2中设置预览Surface
private void startCameraPreview(Surface surface) {
    try {
        CaptureRequest.Builder builder = 
            cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        builder.addTarget(surface);
        cameraCaptureSession.setRepeatingRequest(builder.build(), null, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

个人经验:surfaceCreated回调里不要做耗时操作。我曾经在这里面初始化Camera,结果导致ANR。正确的做法是在surfaceCreated里只做轻量操作,Camera的打开和配置放到异步线程去做。

性能考量:别被表象迷惑

很多人觉得TextureView功能多,那就无脑用TextureView呗。其实不然。性能上的差异在实际项目中是很明显的。

SurfaceView的优势在于:

  • 零拷贝渲染:图像数据直接从Camera输出到Surface,不需要经过CPU
  • 独立刷新率:不受View层级刷新频率影响
  • 低延迟:预览延迟通常比TextureView低10-30ms

TextureView的代价在于:

  • 纹理上传:每一帧都需要从GPU纹理读取再合成到View层级
  • 内存开销:内部维护了一个Bitmap缓存,内存占用更大
  • 帧率波动:在复杂UI场景下,帧率可能不稳定

我曾经在一个直播项目里做过对比测试。同样的720p预览,SurfaceView的CPU占用率比TextureView低了约15%,内存少了约20MB。对于低端机来说,这个差距是致命的。

避坑指南:如果你用TextureView做高帧率预览(比如60fps),记得在Android 7.0以上设备测试。低版本设备上TextureView的纹理合成效率很差,容易出现掉帧。我曾经在Android 6.0的设备上踩过这个坑,后来不得不换回SurfaceView。

如何选择?我的建议

嗯,这里我给出一个比较实用的选择策略:

  1. 纯预览场景(扫码、监控、直播推流):用SurfaceView,性能优先
  2. 带UI特效(美颜滤镜、AR贴纸):用TextureView,灵活性优先
  3. 需要截图/录屏:TextureView更方便,因为可以直接从View获取Bitmap
  4. 低端机适配:优先SurfaceView,减少性能压力

最后说一句,没有银弹。每个项目都有自己的特点,选型时要结合实际情况。我个人习惯是:默认用SurfaceView,除非有明确理由才换TextureView。这个原则帮我避免了很多性能问题。

一句话总结:SurfaceView是「快而糙」,TextureView是「慢而精」。选哪个,取决于你的场景更看重什么。

SurfaceView vs TextureView 选型决策树 摄像头预览需求 需要UI特效/动画? 纯预览/性能优先? 需要截图/录屏? 低端机适配? 直播/监控场景? 扫码/简单预览? TextureView SurfaceView SurfaceView SurfaceView 注:实际选型需结合具体项目需求,以上为通用建议
公众号:蓝海资料掘金营,微信deep3321