简体   繁体   中英

Camera is being used after Camera.release() was called after screen rotation

I have an app that takes pictures on a timer. Normally it works fine, except when the screen is rotated while the camera is sleeping. Can anybody tell me why it fails to take a picture after rotating in sleep?

Normally, when the camera goes to sleep and wakes up it executes...

@Override
protected void onPause() {
    super.onPause();
    camera.stopPreview();
    camera.release();
    //camera = null;  //this give me a null object message
}

@Override
protected void onResume() {
    super.onResume();
    camera = Camera.open(cameraId);
    setCameraDisplayOrientation();
    startCameraPreview(surfaceHolder, surfaceView.getWidth(), surfaceView.getHeight());
}

However, when it wakes up after the camera has been rotated in sleep, it first executes onResume(), surfaceChanged(), onPause(), onStop(empty), onDestroy(empty), then the following:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    surfaceView = (SurfaceView) findViewById(R.id.surface);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);  
} 

@Override
protected void onStart() {
    super.onStart();
}

@Override
protected void onResume() {
    super.onResume();
    camera = Camera.open(cameraId);
    setCameraDisplayOrientation();
    startCameraPreview(surfaceHolder, surfaceView.getWidth(), surfaceView.getHeight());
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    camera.stopPreview();
    setCameraDisplayOrientation();
    startCameraPreview(holder, w, h);
}

public void setCameraDisplayOrientation() {
    deviceRotation = getWindowManager().getDefaultDisplay().getRotation();
    int degrees = 0;
    switch(deviceRotation) {
        case Surface.ROTATION_0: degrees=0; break;//vertical
        case Surface.ROTATION_90: degrees=-90; break; //left side
        case Surface.ROTATION_180: degrees=180; break; //upside-down
        case Surface.ROTATION_270: degrees=90; break; //right side
    }
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    displayRotation = info.orientation + degrees;
    camera.setDisplayOrientation(displayRotation); //changes orientation of camera's display
}

public void startCameraPreview(SurfaceHolder holder, int w, int h) {
    double targetRatio = 0;
    switch(deviceRotation) {
        case Surface.ROTATION_0: targetRatio = (double)w/(double)h; break; //vertical
        case Surface.ROTATION_90: targetRatio = (double)h/(double)w; break; //left side
        case Surface.ROTATION_180: targetRatio = (double)w/(double)h; break; //upside-down
        case Surface.ROTATION_270: targetRatio = (double)h/(double)w; break; //right side
    }
    Camera.Parameters p = camera.getParameters();
    List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();
    int optimal_h = 2; //always refers to short length in PreviewSizes
    int optimal_w = 1; //always refers to long length in PreviewSizes
    for(Camera.Size previewSize : previewSizes) {
        if (Math.abs((double)previewSize.height/(double)previewSize.width - targetRatio) <
                Math.abs((double)optimal_h/(double)optimal_w - targetRatio)) {
            optimal_h = previewSize.height;
            optimal_w = previewSize.width;
        }
    }
    p.setPreviewSize(optimal_w, optimal_h); //defines ratio of image preview - sizes can be larger than actual display
    p.set("rotation", displayRotation); //required to orient final jpeg file correctly
    camera.setParameters(p);
    ViewGroup.LayoutParams surfaceParams = surfaceView.getLayoutParams();
    switch(deviceRotation) { //aligns ratio of surface view to ratio of image preview
        case Surface.ROTATION_0:
            surfaceParams.width=ViewGroup.LayoutParams.MATCH_PARENT;
            surfaceParams.height=(int)(w*(double)optimal_w/(double)optimal_h);
            break; //vertical
        case Surface.ROTATION_90:
            surfaceParams.width=(int)(h*(double)optimal_w/(double)optimal_h);
            surfaceParams.height=ViewGroup.LayoutParams.MATCH_PARENT;
            break; //left side
        case Surface.ROTATION_180:
            surfaceParams.width=ViewGroup.LayoutParams.MATCH_PARENT;
            surfaceParams.height=(int)(w*(double)optimal_w/(double)optimal_h);
            break; //upside-down
        case Surface.ROTATION_270:
            surfaceParams.width=(int)(h*(double)optimal_w/(double)optimal_h);
            surfaceParams.height=ViewGroup.LayoutParams.MATCH_PARENT;
            break; //right side
    }
    surfaceView.setLayoutParams(surfaceParams);
    camera.setPreviewDisplay(holder); //required to startPreview
    camera.startPreview();
}

This is not the complete code. This code does produce a few minor image formatting errors, but it still demonstrates the issue. I have stripped some things out for simplicity. The main issue is that when it tries to take a picture after been rotated in sleep it returns an error "Camera is being used after Camera.release() was called". Why is this?

This is really overdue but as I managed to solve a similar problem of mine a minute ago, I thought I'd contribute for the benefit of yourself and anyone else who might be desperately searching Stack.

So when you rotate the device, you are calling onPause and onDestroy, where you are releasing your camera. I noticed you do have camera.open() in your onResume, without a look at your surface-related code I cannot comment. Heres what worked for me.

Firstly, the cameraPreview

`

public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
    try {
        this.mCamera.setPreviewDisplay(surfaceHolder);
        this.mCamera.startPreview();
    } catch (Exception e) {
    }
}


public void surfaceCreated(SurfaceHolder surfaceHolder) {
    try {
        //TODO we need this here too because on SurfaceCreated we always need to open the camera, in case its released

        this.mCamera.setPreviewDisplay(surfaceHolder);
        this.mCamera.setDisplayOrientation(90);
        //this.mCamera.startPreview();
    } catch (IOException e) {
    }
}

Next, the CameraActivity's Lifecycle code

 @Override
public void onResume() {
    super.onResume();
   try{
       mCamera = openFrontFacingCameraGingerbread();
      // Add to Framelayout
       this.mCameraPreview = new CameraPreview(this, this.mCamera);
        mImage.removeAllViews();
       this.mImage.addView(this.mCameraPreview);

   }catch (RuntimeException ex){

    }



}


@Override
public void onPause() {
    super.onPause();
    captureButton.setText("Begin Capture");
    if(CameraActivity.this.timer !=null) {
        CameraActivity.this.timer.cancel();
        CameraActivity.this.timer.purge();
        CameraActivity.this.timer = null;
    }
    if (mCamera != null) {
        mCamera.setPreviewCallback(null);
        mCameraPreview.getHolder().removeCallback(mCameraPreview);
        mCamera.release();
        mCamera = null;
    }


}


@Override
protected void onDestroy(){
    super.onDestroy();
    releaseCameraAndPreview();
}

private void releaseCameraAndPreview() {

    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
    if(mCameraPreview != null){
        mCameraPreview.destroyDrawingCache();
        mCameraPreview.mCamera = null;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM