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

手电筒App触发setTorchMode-IllegalArgumentException崩溃求助

手电筒App Camera2 API崩溃问题分析与修复

崩溃日志类型

类型1:无效相机ID

Fatal Exception: java.lang.IllegalArgumentException: setTorchMode:2297: Camera ID "0" is a not valid camera ID
       at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:1332)
       at android.hardware.camera2.CameraManager$CameraManagerGlobal.setTorchMode(CameraManager.java:1886)
       at android.hardware.camera2.CameraManager.setTorchMode(CameraManager.java:943)
       at AccService2.onSensorChanged(AccService2.java:197)
       at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:1004)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:335)
       at android.os.Looper.loop(Looper.java:206)
       at android.app.ActivityThread.main(ActivityThread.java:8653)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

类型2:相机无闪光灯单元

Fatal Exception: java.lang.IllegalArgumentException: setTorchMode:2721: Camera "1" does not have a flash unit
       at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:1723)
       at android.hardware.camera2.CameraManager$CameraManagerGlobal.setTorchMode(CameraManager.java:2318)
       at android.hardware.camera2.CameraManager.setTorchMode(CameraManager.java:1211)
       at AccService2.onSensorChanged(AccService2.java:197)
       at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:991)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:335)
       at android.os.Looper.loopOnce(Looper.java:186)
       at android.os.Looper.loop(Looper.java:313)
       at android.app.ActivityThread.main(ActivityThread.java:8757)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)

当前核心代码逻辑

1. 获取带闪光灯的后置相机ID

public class CamId {
    public String getFirstCameraIdFacing(CameraManager cameraManager, @Nullable Integer facing) {
        if (facing == null) facing = CameraMetadata.LENS_FACING_BACK;
        String cameraId = null;
        try {
            String[] cameraIdList = cameraManager.getCameraIdList();
            for (String id : cameraIdList) {
                CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
                if ( characteristics.get(CameraCharacteristics.LENS_FACING).equals(facing) &&
                        characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
                        cameraId = id;
                        break;
                    }
            }
            if(cameraId == null && cameraIdList.length>0) {
                cameraId = cameraIdList[0];
            }
        } catch (CameraAccessException e) {
            Log.e("CameraId ex", "getFirstCameraIdFacing: " + e.getMessage());
        }
        return cameraId;
    }
}

2. 闪光灯可用性监听

public void callBack(){
        torchCallback = new CameraManager.TorchCallback() {
            @Override
            public void onTorchModeUnavailable(@NonNull String cameraId) {
                super.onTorchModeUnavailable(cameraId);
                    Flash_Available = false;
            }
            @Override
            public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
                super.onTorchModeChanged(cameraId, enabled);
                flashState = enabled;
                    Flash_Available = true;
            }
        };
        camManager.registerTorchCallback(torchCallback, null);
    }

3. 调用setTorchMode前的校验

sCameraId = MAcamID.getFirstCameraIdFacing(camManager,null);
if (Flash_Available) {
    String Cam_id=sCameraId;
    if (Cam_id != null) {
        try {
            camManager.setTorchMode(Cam_id, !flashState);
        } catch (CameraAccessException e) {
            Log.e("TAG", "settorchmode Excep", e);
        }
    }
}

崩溃原因分析

  1. 相机ID时效性失效:获取相机ID后,设备相机状态可能发生变化(如外接摄像头移除、系统相机资源被抢占、系统更新导致ID失效),但代码未实时校验当前ID有效性。
  2. Flash_Available状态误判:
    • TorchCallback的onTorchModeChanged无条件设Flash_Available为true,但该回调可能由其他相机的状态变化触发,无法确保当前使用的相机闪光灯可用。
    • onTorchModeUnavailable仅全局设置状态,未关联当前使用的相机ID,状态更新不精准。
  3. fallback逻辑风险:找不到带闪光灯的后置相机时,直接返回第一个相机ID,该相机可能本身无闪光灯,后续调用setTorchMode触发崩溃。
  4. 时序窗口问题:获取ID、校验状态、调用setTorchMode之间存在时间差,窗口内相机状态可能已变化,导致校验通过但调用时失效。

修复方案

1. 实时校验相机有效性与闪光灯状态

每次调用setTorchMode前,重新校验当前相机ID的有效性和闪光灯状态,不依赖缓存结果:

sCameraId = MAcamID.getFirstCameraIdFacing(camManager,null);
if (sCameraId != null) {
    try {
        CameraCharacteristics characteristics = camManager.getCameraCharacteristics(sCameraId);
        Boolean hasFlash = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
        boolean isCameraIdValid = Arrays.asList(camManager.getCameraIdList()).contains(sCameraId);
        
        if (hasFlash != null && hasFlash && isCameraIdValid) {
            camManager.setTorchMode(sCameraId, !flashState);
        }
    } catch (CameraAccessException e) {
        Log.e("TAG", "settorchmode Excep", e);
    }
}

2. 修正TorchCallback状态判断逻辑

仅针对当前使用的相机ID更新状态,避免误判:

torchCallback = new CameraManager.TorchCallback() {
    @Override
    public void onTorchModeUnavailable(@NonNull String cameraId) {
        super.onTorchModeUnavailable(cameraId);
        if (cameraId.equals(sCameraId)) {
            Flash_Available = false;
        }
    }
    @Override
    public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
        super.onTorchModeChanged(cameraId, enabled);
        if (cameraId.equals(sCameraId)) {
            flashState = enabled;
            try {
                CameraCharacteristics characteristics = camManager.getCameraCharacteristics(cameraId);
                Boolean hasFlash = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                Flash_Available = hasFlash != null && hasFlash;
            } catch (CameraAccessException e) {
                Flash_Available = false;
            }
        }
    }
};

3. 移除不安全的fallback逻辑

找不到带闪光灯的相机时直接返回null,避免调用无闪光灯的设备:

public String getFirstCameraIdFacing(CameraManager cameraManager, @Nullable Integer facing) {
    if (facing == null) facing = CameraMetadata.LENS_FACING_BACK;
    String cameraId = null;
    try {
        String[] cameraIdList = cameraManager.getCameraIdList();
        for (String id : cameraIdList) {
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
            if ( characteristics.get(CameraCharacteristics.LENS_FACING).equals(facing) &&
                    characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
                    cameraId = id;
                    break;
                }
        }
        // 移除原fallback逻辑
    } catch (CameraAccessException e) {
        Log.e("CameraId ex", "getFirstCameraIdFacing: " + e.getMessage());
    }
    return cameraId;
}

4. 捕获IllegalArgumentException异常

即使做了前置校验,仍可能因系统底层变化触发崩溃,增加异常捕获避免App闪退:

try {
    camManager.setTorchMode(sCameraId, !flashState);
} catch (CameraAccessException e) {
    Log.e("TAG", "settorchmode Excep", e);
} catch (IllegalArgumentException e) {
    Log.e("TAG", "Invalid camera ID or no flash", e);
    // 可在此重新获取相机ID重试,或提示用户闪光灯不可用
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 11:03:18