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

如何借助Mobile Vision API实现手电筒的开启与关闭?

解决Mobile Vision API中CameraSource与CameraManager手电筒冲突问题

问题描述

使用Mobile Vision API实现文字识别时,尝试通过CameraManager控制手电筒,虽能成功开启,但调用setTorchMode(mCameraId, false)无法关闭,推测是CameraSource与CameraManager同时抢占相机资源导致冲突。

可行解决办法

方案1:反射操作CameraSource内部相机实例

CameraSource未公开闪光灯控制API,可通过反射获取其内部相机对象(兼容旧版Camera和新版camera2 API),直接操作闪光灯模式,避免与CameraManager的资源冲突。

步骤1:补充权限与状态变量

在AndroidManifest.xml中添加闪光灯权限:

<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />

在MainActivity中添加状态标记:

private boolean isFlashOn = false;

步骤2:实现手电筒切换方法

private void toggleFlash() {
    try {
        // 尝试反射获取旧版Camera实例
        Field cameraField = CameraSource.class.getDeclaredField("mCamera");
        cameraField.setAccessible(true);
        Camera mCamera = (Camera) cameraField.get(cameraSource);
        
        if (mCamera != null) {
            Camera.Parameters params = mCamera.getParameters();
            if (isFlashOn) {
                params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                isFlashOn = false;
            } else {
                params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                isFlashOn = true;
            }
            mCamera.setParameters(params);
            return;
        }
    } catch (NoSuchFieldException | IllegalAccessException e) {
        // 旧版API反射失败,尝试camera2 API
        try {
            Field cameraDeviceField = CameraSource.class.getDeclaredField("mCameraDevice");
            cameraDeviceField.setAccessible(true);
            CameraDevice cameraDevice = (CameraDevice) cameraDeviceField.get(cameraSource);
            
            if (cameraDevice != null) {
                CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                if (isFlashOn) {
                    builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                    isFlashOn = false;
                } else {
                    builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                    isFlashOn = true;
                }
                cameraDevice.setRepeatingRequest(builder.build(), null, null);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

步骤3:添加触发按钮

修改activity_main.xml,增加切换按钮:

<RelativeLayout ...>
    <!-- 原有SurfaceView和TextView -->
    
    <Button
        android:id="@+id/flash_toggle_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:text="切换手电筒" />
</RelativeLayout>

在MainActivity的onCreate中绑定点击事件:

Button flashBtn = findViewById(R.id.flash_toggle_btn);
flashBtn.setOnClickListener(v -> toggleFlash());

方案2:自定义CameraSource(更稳定)

Google的CameraSource为开源代码,可将其源码复制到项目中,直接添加控制闪光灯的公开方法,避免反射的兼容性问题。核心逻辑是在自定义CameraSource中新增setFlashMode方法,直接操作内部相机实例切换闪光灯状态。

原理说明

CameraSource启动后会独占相机资源,此时CameraManager无法正常修改该相机的手电筒状态。通过反射或自定义CameraSource操作同一相机实例,能确保闪光灯控制命令直接作用于当前正在使用的相机,避免资源冲突。

内容的提问来源于stack exchange,提问作者Clint William Theron

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:57:04