12

I have an application where I use devices camera.

Now I only release camera in normal flow.

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

Thus, then application exits in camera mode in unexpected way - i.e. Force Close (due to OutOfMemoryError) - camera gets locked. And only way to release it is to restart device.

And after application is started I get: RuntimeException: Fail to connect to camera service

How could I make sure, that camera is released in any case?

Martynas Jurkus
  • 9,231
  • 13
  • 59
  • 101
  • Did you try uninstalling your application? If I remember correctly, this helped me in the past. – vRallev Jun 26 '13 at 11:21
  • That is not what I asked. I need to make sure that `Camera` is released in any case. Without uninstalling application or restarting device. – Martynas Jurkus Jun 26 '13 at 11:23
  • 5
    My guess is that you will need to use `Thread.setDefaultUncaughtExceptionHandler()` to arrange to get control on such crashes to be able to close the camera. – CommonsWare Jun 26 '13 at 11:36
  • Yep, that will do it. Or if you're using Bugsense - let your activity implement `com.bugsense.trace.ExceptionCallback` and release camera in `lastBreath()` – Martynas Jurkus Jun 26 '13 at 12:01

3 Answers3

4

As @CommonsWare suggested, if you want to make sure, that your application releases Camera before crashing you should use Thread.setDefaultUncaughtExceptionHandler().

Or if you're using 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();
        }
    }
} 
Martynas Jurkus
  • 9,231
  • 13
  • 59
  • 101
4

Since the best way to keep a portion of code so that you find it later is to publish it in the 'net,

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;
    }
}

and, in the appropriate places on the main thread:

    mUnexpectedTerminationHelper.init();

and

    mUnexpectedTerminationHelper.fini();
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • Is this all the code necessary? Where would I run the code to close the camera? Why isn't that in the uncaughtexception handler code itself? Do you have a link to more information on this? – msj121 Oct 22 '15 at 13:03
  • @msj121 OOP is about separation of responsibilities. This helper is responsible for reaction on uncaught exceptions. Another helper should be responsible for the camera stuff (you see that `XXXX.closeCamera();` line). In the simplest case of one Activity, you put `XXXX.openCamera()` and `mUnexpectedTerminationHelper.init();` in _onResume()_ and place the closing stuff in _onPause()_. Note that you call `XXXX.closeCamera();` both from the helper and from _onPause()_. Real world applications are usually more complex than just one Activity and include stuff that cannot be easily explained. – 18446744073709551615 Oct 22 '15 at 14:11
  • Sorry I missed the line for close camera. Thanks – msj121 Oct 23 '15 at 00:24
0

Out of memory error comes because the image you tried to save exeeded the limit, normally comes when you try to process a bitmap.

You can try these methods to avoid camera getting not released.

Camera myCamera;

Use logs and fing where the error occurs and Add a try catch block and in the catch block add myCamera.stopPreview(); and myCamera.release(); Also override the ondestroy and onpause method and add myCamera.stopPreview(); and myCamera.release();

Hope this helps you or atleast gave you an idea.

Amalan Dhananjayan
  • 2,277
  • 1
  • 34
  • 47
  • 1
    I'm using logging to determine where `OutOfMemoryError` occurs, but problem still remains - user should not suffer because of my errors. I will handle all errors in the long run, but I want to release camera even though application crashes. – Martynas Jurkus Jun 26 '13 at 12:20