相机开启时调用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 } }
注意事项
- 确保已在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" /> - 动态申请
CAMERA权限(Android 6.0及以上),否则无法访问相机及闪光灯资源。
内容的提问来源于stack exchange,提问作者Wafi_ck
相关产品推荐
相关产品推荐

