method called after release() exception unable to resume with android camera

JavaAndroidExceptionCallbackCamera

Java Problem Overview


While developing a camera app I've encountered an exception that only happened when I switch to other app (onPause() for my app).

01-15 17:22:15.017: E/AndroidRuntime(14336): FATAL EXCEPTION: main
01-15 17:22:15.017: E/AndroidRuntime(14336): java.lang.RuntimeException: Method called after release()
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.hardware.Camera.setPreviewDisplay(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.hardware.Camera.setPreviewDisplay(Camera.java:357)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at com.sora.cbir.yuki.image.leaf.CameraPreview.surfaceCreated(CameraPreview.java:32)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.SurfaceView.updateWindow(SurfaceView.java:551)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:213)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.View.dispatchWindowVisibilityChanged(View.java:4075)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.ViewRoot.performTraversals(ViewRoot.java:858)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.view.ViewRoot.handleMessage(ViewRoot.java:1995)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.os.Handler.dispatchMessage(Handler.java:99)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.os.Looper.loop(Looper.java:150)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at android.app.ActivityThread.main(ActivityThread.java:4389)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at java.lang.reflect.Method.invokeNative(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at java.lang.reflect.Method.invoke(Method.java:507)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
01-15 17:22:15.017: E/AndroidRuntime(14336): 	at dalvik.system.NativeStart.main(Native Method)

I did some research and found out that I need to add

mCamera.setPreviewCallback(null);

as a workaround for Android's camera stack

my onPause() now looks like this:

@Override
protected void onPause() {
    super.onPause();
    try
    {    
    	// release the camera immediately on pause event   
    	//releaseCamera();
    	 mCamera.stopPreview(); 
    	 mCamera.setPreviewCallback(null);
    	 mCamera.release();
    	 mCamera = null;

    }
    catch(Exception e)
    {
    	e.printStackTrace();
    }
}

and my onResume():

@Override
protected void onResume()
{
	super.onResume();
	try
	{
		mCamera.setPreviewCallback(null);
		mCamera = getCameraInstance();
		//mCamera.setPreviewCallback(null);
        mPreview = new CameraPreview(Imageupload.this, mCamera);//set preview
        preview.addView(mPreview);
    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}	
}

and finally my getCameraInstance() method:

public Camera getCameraInstance(){
    Camera camera = null;
    try {
        camera = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    Camera.Parameters parameters = camera.getParameters();
    //mPreviewSize = getBestPreviewSize(parameters, wt, ht);
    //mPictureSize = getBestPictureSize(parameters, wt, ht);
    //Shift W & H => if camera rotates 90 deg
    
    mPreviewSize = getOptimalPreviewSize(parameters, wt, ht); //original => wt,ht
    mPictureSize = getOptimalPictureSize(parameters, wt, ht); //original => wt,ht
    
    Log.d("CAMERA", "SCREEN RESOLUTION H: "+ht);
    Log.d("CAMERA", "SCREEN RESOLUTION W: "+wt);
    
    Log.d("CAMERA", "PREVIEW RESOLUTION H: "+mPreviewSize.height);
    Log.d("CAMERA", "PREVIEW RESOLUTION W: "+mPreviewSize.width);
    
    Log.d("CAMERA", "PICTURE RESOLUTION H: "+mPictureSize.height);
    Log.d("CAMERA", "PICTURE RESOLUTION W: "+mPictureSize.width);
    //set preview size based on device screen
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    //set picture size based on device screen
    parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
    //set output camera mode
    parameters.setPictureFormat(PixelFormat.JPEG);
    //set focous mode
    parameters.setFocusMode(FOCUS_MODE_AUTO);
    //set flash mode
    parameters.setFlashMode("auto");
    List<int[]> fps = parameters.getSupportedPreviewFpsRange();
    //System.out.println("FPS size: " +fps.size());
    //System.out.println("MAX FPS:"+(fps.get(fps.size()-1)[1])/1000);
    //log min and max camera supported fps
    Log.d("CAMERA", "CAMERA MAX FPS: "+(fps.get(fps.size()-1)[1])/1000);
    Log.d("CAMERA", "CAMERA MIN FPS: "+(fps.get(fps.size()-1)[0])/1000);
    if(camera_fps)
    {
    	parameters.setPreviewFpsRange(fps.get(fps.size()-1)[1], fps.get(fps.size()-1)[1]);
    }
    //set camera parameters
    camera.setParameters(parameters);
    
    Toast.makeText(getApplicationContext(), "Your device are capable of previewing @" + fps.get(fps.size()-1)[1]/1000+"fps!",Toast.LENGTH_SHORT).show();
    return camera; // returns null if camera is unavailable
}

any ideas on how to fix this?

Java Solutions


Solution 1 - Java

I've got the same problem. mCamera.setPreviewCallback(null); didn't help. In my activity I've added this to releaseCamera:

mPreview.getHolder().removeCallback(mPreview);

and it works now.

Solution 2 - Java

@ookami.kb solution worked for me too, as well as @srunni commented.

public void onPause() {
	super.onPause();
	
	if (mCamera != null) {
    	mCamera.setPreviewCallback(null);
    	mPreview.getHolder().removeCallback(mPreview);
    	mCamera.release();
	}
}

I removed onDestroy method too.

Solution 3 - Java

The docs clearly say that camera.release() releases all camera resources. After this call camera reference can not be used any more.

If you want to use camera again you have to acquire it via a open(int) method.

It's all described in the camera docs.

Solution 4 - Java

To Resume correctly, you need to do this:

@Override
public void onResume() {
    super.onResume();  

    // Get the Camera instance as the activity achieves full user focus
    if (mCamera == null) {
        initializeCamera(); // Local method to handle camera initialization
    }
}



protected void initializeCamera(){
	// Get an instance of Camera Object
    mCamera = getCameraInstance();
    
   // create a basic camera preview class that can be included in a View layout.
    mPreview=new CameraPreview(this,mCamera);
    
    //add your preview class to the FrameLayout element.
    preview.addView(mPreview);

   //Trigger capturing an image by calling the Camera.takePicture() method.
    captureButton.setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // get an image from the camera
                    mCamera.takePicture(null, null, mPicture);
                }
            }
        );
}

And also just to remind that in oncreate() do nothing except defining FrameLayout preview and Button captureButton.

Solution 5 - Java

@Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

    this.getHolder().removeCallback(this);
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
  Log.e("surfaceDestroyed", "surfaceDestroyed");

}

And re initialize the camera in on Resume function.

Solution 6 - Java

Adding to okambi's answer.

This is the function messing everything up when you resume:

 public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

The try{} is not catching the exception being thrown. Namely that mCamera doesn't exist, and then when it tries to call setPreviewDisplay(holder), there is a crash.

So by removing the callback, this surfaceCreated doesn't get called and avoids the crash.

This is VERY POORLY DOCUMENTED by Google.

Solution 7 - Java

I have put

mPreview.getHolder().removeCallback(mPreview);  

between.

mCamera.setPreviewCallback(null);

and

mCamera.release();

and it worked for me.

 @Override
        	protected void onPause() {
        		super.onPause();
        
        		this.saveTextEdits();
        		try {
        			mCamera.stopPreview();
        			mCamera.setPreviewCallback(null);
        			**mPreview.getHolder().removeCallback(mPreview);**
        			mCamera.release();
        			mCamera = null;
        		}catch (Exception e){
        
        		}
        	}

Solution 8 - Java

I faced same issue, i fixed it by

  • Adding mCamera = null; in surfaceDestroyed(SurfaceHolder holder) method of Preview class.

    public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } and

  • Adding

    camera = Camera.open(); camera.startPreview(); params = camera.getParameters(); preview.setCamera(camera); in OnResume() method of my CameraActivity.

Solution 9 - Java

If you got:

> Attempt to invoke virtual method 'void > android.hardware.Camera.setPreviewCallback(android.hardware.Camera$PreviewCallback)' > on a null object reference

I agree with @ookami.kb - mCamera.setPreviewCallback(null); is not enough, behind it also add this:

mCameraView.getHolder().removeCallback(mCameraView);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiontom91136View Question on Stackoverflow
Solution 1 - JavaKirill BubochkinView Answer on Stackoverflow
Solution 2 - JavaNeonigmaView Answer on Stackoverflow
Solution 3 - JavaPeter KnegoView Answer on Stackoverflow
Solution 4 - JavaRichaView Answer on Stackoverflow
Solution 5 - JavaBalaView Answer on Stackoverflow
Solution 6 - JavaAggressorView Answer on Stackoverflow
Solution 7 - JavaranojanView Answer on Stackoverflow
Solution 8 - JavaRahul SharmaView Answer on Stackoverflow
Solution 9 - Javanicolas asinovichView Answer on Stackoverflow