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
Try the code below, instead of overriding onPause() and onResume(), override the onStop() and onRestart(). In the activity lifecycle, onStop() is called when the activity is not Visible and the next lifecycle method call would be to the onRestart(). Have a look at the code below.
@Override
protected void onStop() {
super.onStop();
try {
m_camera.stopPreview();
m_camera.release();
preview.removeView(m_CameraPreview);
/*
m_CameraPreview is the object of the class that looks like this : public class CameraSurfaceView extends SurfaceView implements Callback
*/
}
catch(Exception e)
{
e.printStackTrace();
}
}
@Override
protected void onRestart() {
super.onRestart();
m_camera=getCameraInstance();//Initialize the camera in your own way
m_CameraPreview = new CameraSurfaceView(this, m_camera);
preview = (FrameLayout)findViewById(R.id.camera_preview);
preview.addView(this.m_CameraPreview);
/*
*camera_preview is the id of the framelayout defined in xml file and preview is *the instance of FrameLayout.
*/
}
As Dan said, the frame layout will have a hold to the previous camera instance and its' surfaceview callbacks will be created in addition to the new objects creating a race condition. Hence you would need to release it in onStop() and reinitialize in onRestart(). Hope this helps.
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
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.
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!
I was getting same error. Below sequence solves my problem.
Call getHolder().removeCallback(this);
in surfaceDestroyed()
Call
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
if(mPreview != null){
mPreview.destroyDrawingCache();
mPreview.mCamera = null;
}
}
in onPause
Call
private boolean safeCameraOpenInView(View view) {
boolean qOpened = false;
releaseCameraAndPreview();
mCamera = getCameraInstance();
mCameraView = view;
qOpened = (mCamera != null);
if(qOpened == true){
mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera,view);
preview = (FrameLayout) view.findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPreview.startCameraPreview();
}
return qOpened;
}
in onCreateView()
.