Android 强制关闭后相机被锁定

12

我有一个应用程序,其中使用了设备相机。

现在我只在正常流程中释放相机。

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    if(camera != null) {
        camera.stopPreview();
        camera.release();
    } 
} 

因此,应用程序在相机模式下以意外的方式退出 - 即强制关闭(由于OutOfMemoryError),导致相机被锁定。唯一释放它的方法是重新启动设备。

在应用程序启动后,我会收到以下消息:RuntimeException: Fail to connect to camera service

我该如何确保相机在任何情况下都被释放?


你尝试卸载你的应用程序了吗?如果我没记错的话,这在过去帮助过我。 - vRallev
那不是我要的。我需要确保在任何情况下都释放 Camera,而无需卸载应用程序或重新启动设备。 - Martynas Jurkus
5
我猜你需要使用Thread.setDefaultUncaughtExceptionHandler()来安排处理这样的崩溃,以便能够关闭摄像头。 - CommonsWare
没错,就是这样。或者如果你正在使用Bugsense - 让你的活动实现com.bugsense.trace.ExceptionCallback并在lastBreath()中释放相机。 - Martynas Jurkus
4个回答

4
正如@CommonsWare所建议的那样,如果您想确保在应用程序崩溃前释放相机,则应使用 Thread.setDefaultUncaughtExceptionHandler()
或者,如果您正在使用Bugsense:
private class MyCameraActivity extends Activity implements SurfaceHolder.Callback, ExceptionCallback {

    @Override
    protected void onCreate(Bundle sSavedInstanceState) {
        super.onCreate(sSavedInstanceState);

        BugSenseHandler.setExceptionCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        this.camera = open();

        try {
            camera.setPreviewDisplay(holder);
        } catch (IOException e) {
            Log.e(TAG, e.getMessage(), e);
        }

        // other camera stuff
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        releaseCamera();
    }

    @Override
    public void lastBreath() {
        releaseCamera();
    }

    private void releaseCamera() {
        if (camera != null) {
            camera.stopPreview();
            camera.release();
        }
    }
} 

4
“由于保留代码片段以便日后查找的最佳方式是将其发布到网络上。”
private UnexpectedTerminationHelper mUnexpectedTerminationHelper = new UnexpectedTerminationHelper();
private class UnexpectedTerminationHelper {
    private Thread mThread;
    private Thread.UncaughtExceptionHandler mOldUncaughtExceptionHandler = null;
    private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread thread, Throwable ex) { // gets called on the same (main) thread
            XXXX.closeCamera(); // TODO: write appropriate code here
            if(mOldUncaughtExceptionHandler != null) {
                // it displays the "force close" dialog
                mOldUncaughtExceptionHandler.uncaughtException(thread, ex);
            }
        }
    };
    void init() {
        mThread = Thread.currentThread();
        mOldUncaughtExceptionHandler = mThread.getUncaughtExceptionHandler();
        mThread.setUncaughtExceptionHandler(mUncaughtExceptionHandler);
    }
    void fini() {
        mThread.setUncaughtExceptionHandler(mOldUncaughtExceptionHandler);
        mOldUncaughtExceptionHandler = null;
        mThread = null;
    }
}

在主线程的适当位置:
    mUnexpectedTerminationHelper.init();

并且

    mUnexpectedTerminationHelper.fini();

这是所有必要的代码吗?我应该在哪里运行代码来关闭相机?为什么不把它放在未捕获异常处理程序代码本身中?你有更多相关信息的链接吗? - msj121
@msj121 OOP 的核心是责任分离。这个帮助类负责对未捕获的异常做出反应。另一个帮助类应该负责相机相关的事情(你可以看到 XXXX.closeCamera(); 这一行)。在最简单的情况下,如果只有一个 Activity,你可以将 XXXX.openCamera()mUnexpectedTerminationHelper.init(); 放在 onResume() 中,并将关闭相机的代码放在 onPause() 中。请注意,你需要在帮助类和 onPause() 中都调用 XXXX.closeCamera();。现实世界中的应用程序通常比一个 Activity 更复杂,并包含无法轻易解释的内容。 - 18446744073709551615
抱歉,我错过了关闭相机的代码行。谢谢。 - msj121

0

内存不足错误是因为您尝试保存的图像超过了限制,通常在尝试处理位图时出现。

您可以尝试以下方法来避免相机未释放:

Camera myCamera;

使用日志并找到错误发生的位置,添加try catch块,在catch块中添加myCamera.stopPreview();myCamera.release();。同时重写ondestroy和onpause方法,并添加myCamera.stopPreview();myCamera.release();

希望这能帮助您或至少给您提供了一个想法。


1
我正在使用日志记录来确定 OutOfMemoryError 发生的位置,但问题仍然存在 - 用户不应该因为我的错误而遭受痛苦。最终我会处理所有的错误,但即使应用程序崩溃,我也想释放相机。 - Martynas Jurkus

-3
private void stopPreviewAndFreeCamera() {

if (mCamera != null) {
    /*
      Call stopPreview() to stop updating the preview surface.
    */
    mCamera.stopPreview();

    /*
      Important: Call release() to release the camera for use by other applications. 
      Applications should release the camera immediately in onPause() (and re-open() it in
      onResume()).
    */
    mCamera.release();

    mCamera = null;
}}

像这样做。

我猜你没有把这段代码放进去,即 mCamera = null; - undefined
1
删除对对象的引用并不意味着相机已被释放。 - Martynas Jurkus
@MartynasJurkus 把你的相机变量设为 null。就像我做的一样。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接