You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

相机开启时调用Torch触发CameraAccessException问题求助

解决相机活跃时调用Torch抛出CAMERA_IN_USE异常的问题

问题原因

当应用内启动相机并创建了预览会话(无论是Camera2还是旧Camera API),相机硬件资源(包括闪光灯)会被当前活跃的相机会话独占。此时再通过CameraManager.setTorchMode()操作闪光灯,就会触发CAMERA_IN_USE异常——因为Torch属于相机硬件的一部分,已被活跃会话占用,无法被CameraManager直接访问。

解决方案

需要根据相机的使用方式,分两种场景处理闪光灯控制:

场景1:使用Camera2 API管理相机

重构FlashLight类,让它支持绑定活跃的相机会话,通过CaptureRequest控制闪光灯状态,而不是直接调用CameraManager:

class FlashLight(private val context: Context) {
    private val cameraManager by lazy { context.getSystemService(Context.CAMERA_SERVICE) as CameraManager }
    private val backCameraId by lazy { cameraManager.cameraIdList[0] }
    private var cameraCaptureSession: CameraCaptureSession? = null
    private var cameraDevice: CameraDevice? = null

    // 绑定活跃的相机会话,在相机打开并创建会话后调用
    fun attachCameraSession(session: CameraCaptureSession, device: CameraDevice) {
        cameraCaptureSession = session
        cameraDevice = device
    }

    fun turnOnFlashLight() {
        // 优先通过相机会话控制闪光灯
        cameraCaptureSession?.let { session ->
            try {
                val requestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) ?: return
                // 关闭自动曝光,强制闪光灯常亮
                requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF)
                requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH)
                session.setRepeatingRequest(requestBuilder.build(), null, null)
            } catch (e: Exception) {
                L.e(e)
            }
            return
        }
        // 相机未活跃时,使用原CameraManager方式
        changeFlashStatus(true)
    }

    fun turnOffFlashLight() {
        cameraCaptureSession?.let { session ->
            try {
                val requestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) ?: return
                // 恢复自动曝光,关闭闪光灯
                requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
                requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
                session.setRepeatingRequest(requestBuilder.build(), null, null)
            } catch (e: Exception) {
                L.e(e)
            }
            return
        }
        changeFlashStatus(false)
    }

    private fun changeFlashStatus(shouldBeTurnedOn: Boolean) {
        try {
            cameraManager.setTorchMode(backCameraId, shouldBeTurnedOn)
        } catch (e: Exception) {
            L.e(e)
        }
    }

    // 相机释放时调用,清空会话引用
    fun detachCameraSession() {
        cameraCaptureSession = null
        cameraDevice = null
    }
}

使用说明

在相机初始化流程中,创建完CameraCaptureSession后,调用flashLight.attachCameraSession(session, cameraDevice)绑定会话;相机释放时调用flashLight.detachCameraSession()。

场景2:使用旧Camera API(android.hardware.Camera)

如果应用使用的是旧版Camera API,直接通过Camera.Parameters控制闪光灯:

class FlashLight(private val context: Context) {
    private val cameraManager by lazy { context.getSystemService(Context.CAMERA_SERVICE) as CameraManager }
    private val backCameraId by lazy { cameraManager.cameraIdList[0] }
    private var camera: android.hardware.Camera? = null

    fun attachCamera(cameraInstance: android.hardware.Camera) {
        camera = cameraInstance
    }

    fun turnOnFlashLight() {
        camera?.let { cam ->
            try {
                val params = cam.parameters
                params.flashMode = android.hardware.Camera.Parameters.FLASH_MODE_TORCH
                cam.parameters = params
            } catch (e: Exception) {
                L.e(e)
            }
            return
        }
        changeFlashStatus(true)
    }

    fun turnOffFlashLight() {
        camera?.let { cam ->
            try {
                val params = cam.parameters
                params.flashMode = android.hardware.Camera.Parameters.FLASH_MODE_OFF
                cam.parameters = params
            } catch (e: Exception) {
                L.e(e)
            }
            return
        }
        changeFlashStatus(false)
    }

    private fun changeFlashStatus(shouldBeTurnedOn: Boolean) {
        try {
            cameraManager.setTorchMode(backCameraId, shouldBeTurnedOn)
        } catch (e: Exception) {
            L.e(e)
        }
    }

    fun detachCamera() {
        camera = null
    }
}

注意事项

  1. 确保已在Manifest中添加必要权限:
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.flash" />
    
  2. 动态申请CAMERA权限(Android 6.0及以上),否则无法访问相机及闪光灯资源。

内容的提问来源于stack exchange,提问作者Wafi_ck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 18:05:22