14. 闪光灯控制:检测闪光灯可用性、设置闪光灯模式(ON/OFF/AUTO/TORCH)、拍照时闪光灯同步

闪光灯控制,听起来好像就是「开灯关灯」那么简单。但实际做起来,坑还真不少。

我记得刚接手一个扫码项目时,产品经理说「闪光灯不就是调一下API吗?」。结果呢?有的手机在低电量下直接不支持闪光灯,有的手机TORCH模式和拍照闪光完全是两套逻辑。嗯,今天我们就来把这些事情彻底理清楚。

14.1 检测闪光灯可用性

你想想看,如果手机压根没有闪光灯,或者闪光灯被系统禁用了,你直接去调用,那肯定要出问题。所以第一步,永远是检测。

在Android中,检测闪光灯是否可用,主要靠 CameraManagergetCameraCharacteristics() 方法。关键字段是 FLASH_INFO_AVAILABLE

// 检测闪光灯是否可用
fun isFlashAvailable(cameraId: String): Boolean {
    val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    val characteristics = cameraManager.getCameraCharacteristics(cameraId)
    val flashAvailable = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
    return flashAvailable ?: false
}

这里有个细节:FLASH_INFO_AVAILABLE 返回的是 Boolean 类型,但可能为 null。所以一定要做空安全处理。我在项目中就遇到过某款低端机,这个字段直接返回 null,结果没做判断,App 直接崩了。

注意: 闪光灯可用性不仅取决于硬件,还受系统状态影响。比如正在通话中、低电量模式,系统可能会禁用闪光灯。建议在每次需要操作闪光灯前都重新检测一次。

14.2 闪光灯模式:ON / OFF / AUTO / TORCH

Android 的闪光灯模式,说白了就两种场景:

  • 拍照闪光:按下快门那一瞬间闪一下。对应 ONOFFAUTO
  • 持续照明:像手电筒一样一直亮着。对应 TORCH

这两套逻辑是完全分开的。我刚开始做的时候,以为设置 FLASH_MODE_TORCH 就能让拍照时也亮着,结果拍出来的照片一片漆黑。后来才明白,TORCH 和拍照闪光根本是两回事。

14.2.1 设置拍照闪光模式

拍照闪光模式是通过 CaptureRequestFLASH_MODE 字段控制的。它有三个值:

模式 说明
OFF 0 关闭闪光灯,即使环境再暗也不闪
SINGLE 1 强制闪光,每次拍照都闪
TORCH 2 持续亮灯,但注意:这不会触发拍照闪光

等等,你可能发现了——AUTO 模式去哪了?

其实 AUTO 模式不是通过 FLASH_MODE 设置的,而是通过 CONTROL_AE_MODE(自动曝光模式)来控制的。具体来说:

// 设置 AUTO 闪光模式
val requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)

// 设置强制闪光模式
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE)
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)

// 设置关闭闪光模式
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
核心要点: AUTO 模式依赖 AE(自动曝光)算法来判断是否需要闪光。如果你手动设置了 FLASH_MODE_SINGLE,那不管环境多亮,它都会闪。反之,如果你设了 FLASH_MODE_OFF,就算环境再暗,它也不闪。

14.2.2 设置 TORCH 模式

TORCH 模式就是手电筒模式。它和拍照闪光互不干扰。设置方式很简单:

// 开启 TORCH
fun turnOnTorch(cameraId: String) {
    val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    cameraManager.setTorchMode(cameraId, true)
}

// 关闭 TORCH
fun turnOffTorch(cameraId: String) {
    val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    cameraManager.setTorchMode(cameraId, false)
}

这里有个坑:setTorchMode() 是异步操作。你调用后,闪光灯不会立刻亮起。如果你紧接着就去拍照,可能灯还没亮。我曾经在项目中就因为这个原因,拍出来的照片一半亮一半暗。解决方案是监听 TorchCallback,等回调确认灯亮了再拍照。

小技巧: 如果你需要同时使用 TORCH 和拍照闪光,建议先关闭 TORCH,等拍照闪光完成后再重新开启 TORCH。否则两个逻辑可能会打架,导致闪光灯状态异常。

14.3 拍照时闪光灯同步

这是最容易被忽视的地方。很多人以为设置了闪光模式,拍照时就会自动闪。但实际开发中,你需要手动控制闪光灯的触发时机。

为什么?因为 CaptureRequest 只是告诉相机「你该闪了」,但相机什么时候闪,取决于你的请求提交时机。如果你在预览流中设置了 FLASH_MODE_SINGLE,然后立刻提交拍照请求,闪光灯可能还没准备好。

正确的做法是:

  1. 先设置好闪光模式(ON / OFF / AUTO)
  2. 等待至少一帧预览数据(确保设置生效)
  3. 再提交拍照请求
// 拍照时闪光灯同步示例
fun takePhotoWithFlash() {
    // 1. 设置闪光模式为强制闪光
    previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE)
    previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
    previewSession.setRepeatingRequest(previewRequestBuilder.build(), null, null)

    // 2. 等待一帧(实际项目中建议用回调或 Handler 延迟)
    Handler(Looper.getMainLooper()).postDelayed({
        // 3. 提交拍照请求
        captureSession.capture(captureRequestBuilder.build(), captureCallback, null)
    }, 100) // 100ms 的延迟通常足够
}

你可能会问:100ms 够吗?说实话,这个值因手机而异。我测试过一些机型,有的 50ms 就够了,有的需要 200ms。我个人习惯是先用 100ms,如果发现闪光不同步,再适当增加。

重要提醒: 不要在主线程中做耗时操作。上面的 Handler 延迟只是示例,实际项目中建议使用 CameraCaptureSession.CaptureCallbackonCaptureCompleted() 回调来判断设置是否生效。

14.4 知识体系总览

下面这张图,把闪光灯控制的整个流程串起来了。你可以对照着看,心里会更有底。

闪光灯控制知识体系 闪光灯控制 检测闪光灯可用性 FLASH_INFO_AVAILABLE 注意:可能为 null 设置闪光灯模式 拍照闪光:ON/OFF/AUTO 通过 FLASH_MODE + AE_MODE 控制 持续照明:TORCH 通过 setTorchMode() 控制 拍照时闪光同步 先设置模式 → 等待生效 → 拍照 建议使用回调确认状态 三步走:检测 → 设置 → 同步

14.5 避坑指南

最后,分享几个我踩过的坑,希望能帮你少走弯路。

  • 不要同时操作多个 CameraManager 实例:我曾经在同一个页面中创建了两个 CameraManager 实例,结果一个开灯一个关灯,闪光灯疯狂闪烁。后来发现,CameraManager 应该是单例的。
  • TORCH 和拍照闪光不要混用:如果你开启了 TORCH,然后又设置了 FLASH_MODE_SINGLE,拍照时闪光灯可能不会按预期工作。建议先关 TORCH,再拍照,拍完再开 TORCH。
  • 低电量下闪光灯可能被禁用:有些手机在电量低于 15% 时会自动禁用闪光灯。检测可用性时,别忘了监听 ACTION_BATTERY_LOW 广播。
  • 模拟器上闪光灯永远不可用:这个不用我多说了吧?真机调试才是王道。

好了,闪光灯控制这块就讲到这里。内容不算多,但每个点都挺关键的。你只要把检测、设置、同步这三步走顺了,基本就不会出大问题。

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