I have one activity class(CameraActivity) which is using my CameraPreview class. In "OnResume" the camera and preview are initiated. In "OnPause", i am releasing camera resources. When application is started, everything works fine inside the "OnResume" but when i start another activity through intent (E.g. open url in browser) and then come back to my activity then exception is occured inside "OnResume" originating CamerPreview class. Please find below the code:
//CameraActivity class
public void onResume(){
super.onResume();
Log.d("inside onResume, camera==="+mCamera, "inside onResume");
try {
if(mCamera==null)
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
autoFocusHandler = new Handler();
mCamera = getCameraInstance();
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
scanner = new ImageScanner();
scanner.setConfig(0, Config.X_DENSITY, 3);
scanner.setConfig(0, Config.Y_DENSITY, 3);
mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
preview.addView(mPreview);
}
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e("onResume",Log.getStackTraceString(e));
}
public void onPause{
try {
super.onPause();
if (mCamera != null) {
previewing = false;
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
mPreview=null;
}
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e("releaseCamera",Log.getStackTraceString(e));
}
}
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
} catch (Exception e){
Log.e("getCameraInstance",Log.getStackTraceString(e));
}
return c;
}
// Following is CameraPreview Class:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
Camera mCamera;
PreviewCallback previewCallback;
AutoFocusCallback autoFocusCallback;
private int rotation;
public int getRotation() {
return rotation;
}
public void setRotation(int rotation) {
this.rotation = rotation;
}
public CameraPreview(Context context, Camera camera,
PreviewCallback previewCb,
AutoFocusCallback autoFocusCb) {
super(context);
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
if(mCamera==null){
mCamera=Camera.open();
}
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Camera preview released in activity
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* If your preview can change or rotate, take care of those events here.
* Make sure to stop the preview before resizing or reformatting it.
*/
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e){
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
}
This is from logCat:
11-05 10:14:34.585: E/AndroidRuntime(7864): FATAL EXCEPTION: main
11-05 10:14:34.585: E/AndroidRuntime(7864): java.lang.RuntimeException: Method called after release()
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.hardware.Camera.setPreviewDisplay(Native Method)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.hardware.Camera.setPreviewDisplay(Camera.java:393)
11-05 10:14:34.585: E/AndroidRuntime(7864): at com.intagleo.qraugmented.detection.camera.CameraPreview.surfaceCreated(CameraPreview.java:74)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.SurfaceView.updateWindow(SurfaceView.java:552)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:215)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.View.dispatchWindowVisibilityChanged(View.java:4027)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewRoot.performTraversals(ViewRoot.java:790)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.view.ViewRoot.handleMessage(ViewRoot.java:1867)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.os.Handler.dispatchMessage(Handler.java:99)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.os.Looper.loop(Looper.java:130)
11-05 10:14:34.585: E/AndroidRuntime(7864): at android.app.ActivityThread.main(ActivityThread.java:3687)
11-05 10:14:34.585: E/AndroidRuntime(7864): at java.lang.reflect.Method.invokeNative(Native Method)
11-05 10:14:34.585: E/AndroidRuntime(7864): at java.lang.reflect.Method.invoke(Method.java:507)
11-05 10:14:34.585: E/AndroidRuntime(7864): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
11-05 10:14:34.585: E/AndroidRuntime(7864): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
11-05 10:14:34.585: E/AndroidRuntime(7864): at dalvik.system.NativeStart.main(Native Method)
EDIT
I updated "surfaceDestroyed" and put logs as suggested but now i am getting exception in "onPause" --> onSurfaceDestroyed. Initially onPause was executing fine.
1- The camera instance is created in "onResume" of activity class through method "getCameraInstance" and passes mCamera instance to CameraPreview Class. I tried to change it so that camera instance is created only onside "onSurfaceCreated" and assigned back the mCamera instance to the activity class but it did not work. I also noticed through debug that previewCallBack member of "CameraPreview" class is valid the first time but second time the "previewCallBack" member of "CameraPreview" class is null.
Note that first time when "onResume" is called, everything works fine but when it runs second time after onPause then exception is occured originally although code is the same in onResume.
11-06 01:25:28.375: I/onResume(4332): INITIATED
// Workinf fine till now. Now opening another intent activity
11-06 01:26:23.500: I/onPause(4332): INITIATED
11-06 01:26:23.804: "OnSurfaceDestroyed": "Initiated"
11-06 01:26:23.945: E/AndroidRuntime(4332): FATAL EXCEPTION: main
11-06 01:26:23.945: E/AndroidRuntime(4332): java.lang.RuntimeException: Method called after release()
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.hardware.Camera.stopPreview(Native Method)
11-06 01:26:23.945: E/AndroidRuntime(4332): at com.intagleo.qraugmented.detection.camera.CameraPreview.surfaceDestroyed(CameraPreview.java:85)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.SurfaceView.reportSurfaceDestroyed(SurfaceView.java:596)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.SurfaceView.updateWindow(SurfaceView.java:490)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:215)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.View.dispatchWindowVisibilityChanged(View.java:4027)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewRoot.performTraversals(ViewRoot.java:790)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.view.ViewRoot.handleMessage(ViewRoot.java:1867)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.os.Handler.dispatchMessage(Handler.java:99)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.os.Looper.loop(Looper.java:130)
11-06 01:26:23.945: E/AndroidRuntime(4332): at android.app.ActivityThread.main(ActivityThread.java:3687)
11-06 01:26:23.945: E/AndroidRuntime(4332): at java.lang.reflect.Method.invokeNative(Native Method)
11-06 01:26:23.945: E/AndroidRuntime(4332): at java.lang.reflect.Method.invoke(Method.java:507)
11-06 01:26:23.945: E/AndroidRuntime(4332): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
11-06 01:26:23.945: E/AndroidRuntime(4332): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
11-06 01:26:23.945: E/AndroidRuntime(4332): at dalvik.system.NativeStart.main(Native Method)
As you have added the camera to the FrameLayout, like this:
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
preview.addView(mPreview);
The surfaceCreated
method will be called and so mCamera.setPreviewDisplay(holder);
will be called.
When you create/open a new camera, the FrameLayout
still has your previous camera and so its surfaceCreated
will be called in addition to your new camera.
What you should do, is remove your previous camera from FrameLayout
when you release your camera (on onPause()
method) like this:
preview.removeView(mPreview);
Hope it helps.
Dan is right. Also see here.
code sample:
public class MainActivity extends Activity {
private FrameLayout mFlCameraPreview;
private Camera mCamera;
private CameraPreview mCameraPreview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFlCameraPreview = (FrameLayout) findViewById(R.id.main_fl_camera_preview);
}
@Override
protected void onResume() {
super.onResume();
if (mCamera == null) {
mCamera = getCameraInstance();
}
if (mCameraPreview == null) {
mCameraPreview = new CameraPreview(this, mCamera);
mFlCameraPreview.addView(mCameraPreview);
}
}
@Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if (mCameraPreview != null) {
mFlCameraPreview.removeView(mCameraPreview);
mCameraPreview = null;
}
}
public static Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
}
return camera;
}
}
EDIT
This is a tough one to answer, I can't be 100% sure what's causing your exceptions right now. I have included my Camera code below, hopefully that will help, I use startCamera()
and stopCamera()
methods that I call in onPause
and onResume
. I also, only create a new instance of the CameraPreview
class in my onCreate
, I don't re-instantiate in onResume
unless my cameraView == null
. There are a couple things we do differently. Hopefully the code below will help, maybe you can play with it to get yours working:
P.S.: Everything works for me. i.e. Going into other Activities, etc. The only part of the Lifecycle I haven't tested is onDestroy
, but that is because my application is designed to start at the beginning in this cycle.
MainActivity:
boolean cameraReleased = false;
@Override
protected void onPause() {
Log.i("onPause", "CALLED:: cameraReleased = " + cameraReleased);
Log.i("onResume", "CALLED:: cameraView = " + cameraView.toString());
if (cameraReleased == false) {
image = null;
imageResult.setImageBitmap(null);
imageResult.setImageResource(0);
cameraView.stopCamera();
cameraReleased = true;
}
if (cameraView == null) {
Log.i("onPause", "cameraView == null");
cameraView = new JJCameraSurfaceView(getApplicationContext());
imageResult = new ImageView(getApplicationContext());
}
super.onPause();
}
@Override
protected void onDestroy() {
Log.e("onDestroy", "INITIATED");
super.onDestroy();
}
@Override
protected void onResume() {
Log.i("onResume", "CALLED:: cameraReleased = " + cameraReleased);
Log.i("onResume", "CALLED:: cameraView = " + cameraView.toString());
if (cameraReleased == true) {
image = null;
imageResult.setImageBitmap(null);
imageResult.setImageResource(0);
cameraView.startCamera();
}
if (cameraView == null) {
Log.i("onResume", "cameraView == null");
cameraView = new JJCameraPreview(getApplicationContext());
imageResult = new ImageView(getApplicationContext());
}
super.onResume();
}
@Override
public void onBackPressed() {
// If Statement used to get out of my camera view and back to my MainActivity - Same Class
if (“Camera Preview or Image Result is displayed”) {
cameraView.stopCamera();
image = null;
imageResult.setImageBitmap(null);
imageResult.setImageResource(0);
cameraView.startCamera();
return;
}
Log.i("onBackPressed", "WAS PRESSED");
super.onBackPressed();
}
CameraPreview:
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.w("surfaceChanged", "STARTED");
if (camera != null) {
Log.w("surfaceChanged", "camera = NOT NULL");
Camera.Parameters cParams = camera.getParameters();
cParams.setPreviewSize(width, height);
cParams.setSceneMode(Parameters.SCENE_MODE_NIGHT);
camera.setParameters(cParams);
camera.startPreview();
}
}
public void surfaceCreated(SurfaceHolder holder) {
Log.w("surfaceCreated", "STARTED");
if (camera == null) {
camera = Camera.open();
}
try {
camera.setPreviewDisplay(mHolder);
} catch (Exception e) {
Log.e("setPreviewDisplay", "FAILED: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.w("CameraSurfaceDestroyed", "INITIATED");
camera.stopPreview();
camera.release();
camera = null;
}
public void startCamera() {
Log.w("startCamera", "CALLED");
mHolder = getHolder();
surfaceCreated(mHolder);
camera.startPreview();
mHolder.addCallback(this);
}
public void stopCamera() {
mHolder = getHolder();
mHolder.removeCallback(this);
camera.stopPreview();
}
I had a similar problem with my code which was force closing with the Method called after release()
error.
I was calling a SetupCamera()
method in OnResume()
which checked for a null camera
object and then called camera.Open()
.
What fixed my problem was to get rid of the null-check and just call camera.Open()
whether it was null or not (I had already set camera = null
on onPause
) after reading the Camera Docs.
I know this is not definitive in tracking down my problem, but it absolutely worked for me!
My working solution:
First:
In CameraActivity
class declare mCamera
as array:
Camera mCamera[] = new Camera[1];
Second: declaration of the constructor CameraPreview
must look like this:
public CameraPreview(Context context, Camera[] camera,
PreviewCallback previewCb,
AutoFocusCallback autoFocusCb) {
mCamera = camera;
...
}
But mCamera
in CameraPreview
class must be declared as follows:
Camera[] mCamera; // without instantiating of the array!
And finally: in both classes inside all the methods you should replace all references mCamera
by mCamera[0]
P.S: Sorry for my English
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With