method called after release() exception unable to resume with android camera
JavaAndroidExceptionCallbackCameraJava 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);