Administrator
发布于 2026-08-07 / 17 阅读
0
0

架构设计:如果让你设计 App 层相机模块,如何分层(相机管理层、状态机、业务层)

在工业级 Android 应用程序中,直接在业务层调用 Camera2 或 CameraX 会导致代码迅速恶化。设计一个高内聚、低耦合的 App 层相机模块,核心在于将底层硬件的异步回调和状态割裂,转化为业务层可感知的、线性的、确定性的生命周期与数据流。

整体架构建议分为四层:硬件驱动抽象层(Provider)、核心相机管理层(Core Manager)、相机状态机(State Machine) 和 业务隔离层(Interactors / Presenters)。


一、 整体架构拓扑图

┌─────────────────────────────────────────────────────────┐
│              业务层 (Business / UI Layer)               │
│      (Activity / Fragment / Compose, ViewModel)         │
└────────────────────────────┬────────────────────────────┘
                             │ (通过统一契约接口交互)
                             ▼
┌─────────────────────────────────────────────────────────┐
│        业务隔离与用例层 (UseCase / Interactor)           │
│   (处理:扫码业务、美颜录制业务、头像裁剪业务、权限拦截)       │
└────────────────────────────┬────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────┐
│         核心相机管理层 (CameraCoreManager)               │
│   (聚合中心,对外暴露纯净的 API,内置【状态机控制中心】)        │
└──────────────┬───────────────────────────┬──────────────┘
               │ (管理生命周期)             │ (驱动状态流转)
               ▼                           ▼
┌─────────────────────────────┐ ┌─────────────────────────┐
│   生命周期感知器 (Lifecycle)  │ │   相机状态机 (State)    │
└─────────────────────────────┘ └─────────────────────────┘
               │                           │
               ▼                           ▼
┌─────────────────────────────────────────────────────────┐
│         硬件驱动抽象层 (CameraProvider Engine)           │
│  ├─ CameraXImpl (默认引擎)                              │
│  └─ Camera2Impl (专业/老旧机型定制引擎)                   │
└─────────────────────────────────────────────────────────┘

二、 核心分层设计

1. 硬件驱动抽象层 (Hardware Driver / Provider Engine)

  • 职责:彻底屏蔽底层的实现细节(Camera2 或 CameraX)。业务层不应该看到任何 CaptureRequest 或 ProcessCameraProvider。

  • 设计要点:

    • 定义一个统一的统一契约接口 ICameraProvider。

    • 提供两种实现:CameraXProviderImpl(处理 90% 的常规业务,自带厂商 Bug 抹平)和 Camera2ProviderImpl(用于特定高要求机型或需要 OpenGL 特效的场景)。

  • 接口伪代码:

    interface ICameraProvider {
        fun open(cameraId: String, options: CameraOptions)
        fun startPreview(surface: Surface)
        fun takePicture(callback: ImageCaptureCallback)
        fun startRecording(file: File, callback: VideoRecordCallback)
        fun release()
    }
    

2. 相机状态机层 (Camera State Machine)

相机是典型的多状态异步设备,其状态流转极易因为用户快速点击、电话打断、切后台等导致死锁或崩溃。必须引入状态机进行强约束。

  • 职责:管理相机的生命周期和工作流状态,拦截不合法的并发操作。

  • 状态定义 (States):

    • Uninitialized(未初始化)

    • Opening(正在打开)

    • Opened(已打开,硬件就绪)

    • Previewing(预览中)

    • Focusing(对焦中/测光中)

    • Capturing(拍照捕获中)

    • Recording(录像中)

    • Releasing / Released(正在释放/已释放)

  • 设计要点:

    • 采用 MVI / Reducer 思想或简单的状态模式。

    • 动作拦截:当状态为 Capturing 时,如果用户再次狂点拍照按钮触发 CaptureAction,状态机直接拦截并丢弃该 Action,防止底层 Pipeline 队列阻塞。

    • 异步转同步/挂起:使用 Kotlin Coroutines (Mutex) 或 Flow,将相机的异步回调(如 onConfigured)转化为挂起函数,确保状态流转的线性安全。

3. 核心相机管理层 (Camera Core Manager)

  • 职责:整个模块的“大管家”。它聚合了 ICameraProvider、StateMachine 以及 Android 系统的 Jetpack Lifecycle。

  • 设计要点:

    • 生命周期自动宿主(Lifecycle-Aware):通过实现 DefaultLifecycleObserver,自动监听 UI 的 onResume 和 onPause。在 onPause 时,无条件切断状态机并强制触发 release(),从根源上杜绝内存泄漏。

    • 单例与线程池封装:相机的开启和会话建立非常耗时(200ms~500ms),Manager 内部必须维护一个单线程的 CameraExecutor(基于 HandlerThread),确保所有对底层的调用都在非 UI 线程按顺序排队执行。

4. 业务隔离层与用例层 (UseCase / Business Layer)

  • 职责:根据具体的业务场景,定制不同的相机配置组合。

  • 设计要点:

    • 扫码业务 (QrCodeUseCase):Manager 配置为 Preview + ImageAnalysis。Analysis 输出 YUV 数据传给 ZXing/MLKit,不开启拍照和录像功能,分辨率锁定在 1080P 以内以保证算法帧率。

    • 专业相机业务 (ProCameraUseCase):Manager 配置为 Preview + ImageCapture。开启手动 ISO、曝光补偿调节接口,使能 RAW 格式输出。

    • 音视频录制业务 (VideoRecordUseCase):Manager 绑定音频权限、配置 VideoCapture,联动 MediaMuxer 写入 MP4。


三、 架构设计的核心护城河(如何防坑?)

在实际落地这个架构时,你需要特别设计以下三个机制:

  1. 数据流(Data Stream)解耦:

    • 严禁将相机的原始 Image 对象直接透传到业务层。

    • 在抽象层将 Image 转为 Bitmap、NV21 byte[] 或特定包装类。谁消费,谁释放;如果透传到业务层,必须在用例层提供统一的 BufferPool(对象池)进行复用,防止频繁拍照/分析导致 JVM 频繁 GC 造成画面掉帧。

  2. 异常熔断与降级机制(Fallback Strategy):

    • 相机可能因为被其他 App 强占(如微信视频通话时打开你的 App)而报 CameraInUse 错误。

    • Manager 层需捕获此类 Error,向业务层上报统一的 CameraException(val errorCode: Int),业务层据此弹出人性化的提示,而不是直接 Crash。

    • 配置降级:如果请求的 4K 录像分辨率在某些低端机型上引发 Session 建立失败,自动降级为 1080P 重新尝试建立。

这套架构设计采用了下层实现隐藏、中层状态机收拢、上层按业务用例拆分的思路。



评论