24、Camera 状态机:CameraDevice状态机、CaptureSession状态机、状态转换图、非法状态处理

状态机这东西,说白了就是一套「规矩」。

Camera 框架里要是没这套规矩,那系统早就乱套了。你想想看,一个摄像头设备,可能同时被好几个 App 抢着用,谁先谁后?谁该听谁的?

我个人习惯,在分析这类复杂系统时,先看状态机。因为状态机画清楚了,代码逻辑就清晰了一半。

CameraDevice 状态机:设备层面的生命周期

CameraDevice 代表的是物理摄像头。它的状态转换,直接决定了你能不能打开摄像头、能不能开始拍照。

我记得在 Android 5.0 刚引入 Camera2 时,很多开发者抱怨「怎么打开摄像头这么麻烦」。其实不是麻烦,是规矩更严了。

CameraDevice 的状态主要有这几个:

  • UNINITIALIZED:初始状态,啥也没干。
  • OPENED:设备已打开,但还没创建会话。
  • CONFIGURED:已配置好输出流,准备就绪。
  • CAPTURING:正在拍照或录像。
  • CLOSED:已关闭,资源释放。
  • ERROR:出错了,需要重建。

状态转换图大概是这样:

UNINITIALIZED OPENED CONFIGURED CAPTURING CLOSED ERROR open() configure() capture() close() close() 异常 异常

嗯,这里要注意:从 OPENED 到 CONFIGURED,必须调用 createCaptureSession()。如果你直接调用 capture(),系统会抛 IllegalStateException。

⚠️ 避坑指南:

我曾经在项目中遇到过,一个同事在 onOpened 回调里直接调了 capture(),结果崩溃了。他当时还纳闷:「明明设备打开了啊?」

其实问题就在于:设备打开了,但会话还没创建。CaptureSession 才是真正干活的人。

CaptureSession 状态机:会话层面的精细控制

CaptureSession 的状态机比 CameraDevice 更细。因为它要处理请求的排队、重复、中止等操作。

主要状态有:

  • READY:会话已创建,等待接收请求。
  • ACTIVE:正在处理请求(拍照/录像中)。
  • IDLE:请求处理完毕,但会话还在。
  • CLOSED:会话已关闭。
  • ERROR:会话出错。

状态转换图:

READY ACTIVE IDLE CLOSED ERROR capture() close() 完成 capture() 异常

非法状态处理:别让 App 崩溃

状态机最怕什么?最怕非法状态转换。

比如:

  • 在 CLOSED 状态下调 capture()
  • 在 ACTIVE 状态下重复调 configure()
  • 在 ERROR 状态下试图恢复操作

这些操作,系统会怎么处理?

我告诉你,CameraService 会直接抛异常。但抛异常的方式有两种:

异常类型 触发场景 处理方式
IllegalStateException 状态不合法,但可恢复 App 捕获后重试
CameraAccessException 设备级错误,不可恢复 需要重建 CameraDevice
RuntimeException 严重内部错误 建议重启 App
💡 我的经验:

我个人习惯在 App 层做一个「状态守卫」。每次调用 Camera API 前,先检查当前状态是否合法。比如:

if (cameraDevice == null || session == null) {
    Log.w(TAG, "状态不对,跳过本次操作");
    return;
}

这层守卫虽然简单,但能挡住 90% 的非法状态问题。

状态转换的典型场景

咱们看一个实际流程:

  1. App 启动 → 调用 CameraManager.openCamera() → 状态变为 OPENED
  2. 创建 CaptureSession → 状态变为 CONFIGURED
  3. 发送 capture() 请求 → 状态变为 CAPTURING
  4. 拍照完成 → 状态回到 CONFIGURED(或 IDLE)
  5. 关闭相机 → 状态变为 CLOSED

这个流程看起来简单,但实际项目中,状态转换的时机非常关键

我记得有一次,我在做多摄像头切换功能。切换时先 close() 再 open(),但 close() 是异步的。结果在 close() 还没完成时,我就调了 open(),导致状态机混乱。

🔧 解决方案:

用回调来驱动状态转换。不要用「延时」或「轮询」来判断状态。CameraDevice 和 CaptureSession 都提供了回调接口,老老实实在回调里做下一步操作。

状态机的设计哲学

为什么 Android 要搞这么复杂的状态机?

说白了,就是为了安全确定性

你想想看,如果状态不明确,两个 App 同时操作摄像头,谁先谁后?数据会不会乱?

状态机就是一套「交通规则」。红灯停、绿灯行,谁也别乱来。

我个人觉得,理解状态机最好的方式,就是画图。把每个状态、每个转换、每个异常都画出来。画着画着,你就懂了。

📌 核心要点:
  • CameraDevice 状态机:UNINITIALIZED → OPENED → CONFIGURED → CAPTURING → CLOSED
  • CaptureSession 状态机:READY → ACTIVE → IDLE → CLOSED
  • 非法状态处理:用守卫模式 + 回调驱动
  • 不要跳过任何状态,不要假设状态

好了,这一章就到这里。状态机这东西,越用越觉得它设计得巧妙。你只要记住:状态决定行为,行为改变状态


公众号:蓝海资料掘金营,微信deep3321