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

Android应用退后台重启出现Camera.release()后仍使用相机异常

问题分析与解决方案

首先明确:这个异常必须重视。虽然当前应用没有崩溃,但它意味着相机资源的管理逻辑存在漏洞,后续可能引发相机资源泄漏、应用后续操作相机时崩溃,甚至导致系统中其他应用无法正常使用相机——因为Android系统对相机资源的访问是排他性的,不正确的释放/复用逻辑会干扰系统的资源调度。

异常原因分析

从你的日志和描述来看,核心问题是:

  • 应用进入后台(onPause()/onStop())时,你已经调用了Camera.release()释放相机资源,但没有将Camera实例置为null。
  • 当应用从后台回到前台时,你的代码复用了这个已经被释放的Camera实例,调用getParameters()时触发了RuntimeException。
  • 屏幕旋转时没问题,是因为默认配置下屏幕旋转会销毁并重建Activity,所有资源都会重新初始化,相当于从头创建Camera实例,自然不会复用已释放的对象。

具体修复方案

针对这个问题,你需要严格规范Camera实例的生命周期管理,核心是释放后置空,恢复时重建:

1. 正确释放相机资源,务必置空实例

在onPause()(或surfaceDestroyed())中释放相机后,一定要将Camera对象置为null,避免后续代码误引用已失效的实例:

@Override
protected void onPause() {
    super.onPause();
    releaseCamera();
}

private void releaseCamera() {
    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release(); // 释放硬件资源
        mCamera = null;    // 关键:置空,彻底断开引用
    }
}

// 同时在SurfaceHolder的surfaceDestroyed中也做同样处理
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    releaseCamera();
}

2. 恢复时重新创建Camera实例

在onResume()或surfaceCreated()中,不要复用之前的实例,而是重新调用Camera.open()获取新的相机实例:

// 封装获取相机实例的工具方法
private Camera getCameraInstance() {
    Camera camera = null;
    try {
        camera = Camera.open(); // 尝试打开默认相机
    } catch (Exception e) {
        // 相机不可用(被其他应用占用、硬件故障等),可以在这里提示用户
        Log.e(TAG, "Camera is unavailable: " + e.getMessage());
    }
    return camera;
}

// 在surfaceCreated中初始化相机
@Override
public void surfaceCreated(SurfaceHolder holder) {
    mCamera = getCameraInstance();
    if (mCamera == null) {
        // 处理相机无法获取的场景,比如显示错误提示
        return;
    }

    try {
        // 这里可以安全地调用getParameters()了
        Camera.Parameters params = mCamera.getParameters();
        // 根据你的需求设置相机参数(比如预览尺寸、对焦模式等)
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
    } catch (IOException e) {
        // 初始化失败,务必释放相机资源
        releaseCamera();
        Log.e(TAG, "Failed to initialize camera preview: " + e.getMessage());
    }
}

3. 增加防御性检查(可选但推荐)

在任何操作Camera的代码前,先检查实例是否有效,避免意外异常:

private boolean isCameraValid(Camera camera) {
    if (camera == null) {
        return false;
    }
    try {
        // 通过调用一个简单的方法判断相机是否还可用
        camera.getParameters();
        return true;
    } catch (RuntimeException e) {
        // 抛出异常说明相机已经被释放
        return false;
    }
}

为什么屏幕旋转时没问题?

默认情况下,Android屏幕旋转会触发Activity的销毁与重建(onDestroy() -> onCreate()),整个流程会重新初始化所有资源,包括Camera实例——相当于每次旋转都是从头创建相机,自然不会遇到已释放实例的问题。而应用后台恢复时,Activity并没有被销毁,只是从后台回到前台,这时候如果之前的Camera实例没置空,就会被错误复用。

按照上面的方案调整后,你就能彻底解决这个异常,同时避免后续的相机资源问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:31:13