Patrick
Patrick

Reputation: 35234

SurfaceView for Camera Preview won't get destroyed when pressing Power-Button

I want to implement a camera preview. For that I have a custom View CameraView extends ViewGroup that in the constructor programmatically creates an surfaceView.

I have the following components (higly simplified for beverity):

ScannerFragment.java

public View onCreateView(..) {
   //inflate view and get cameraView
}

public void onResume() {
   //open camera -> set rotation -> startPreview (in a thread) -> 
   //set preview callback -> start decoding worker
}

public void onPause() {
   // stop decoding worker -> stop Preview -> release camera
}

CameraView.java extends ViewGroup

public void setUpCalledInConstructor(Context context) {
   //create a surfaceview and add it to this viewgroup ->
   //get SurfaceHolder and set callback
}

/* SurfaceHolder.Callback */
public void surfaceCreated(SurfaceHolder holder) {
   camera.setPreviewDisplay(holder);
}

public void surfaceDestroyed(SurfaceHolder holder) {
    //NOTHING is done here
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    camera.getParameters().setPreviewSize(previewSize.width, previewSize.height);
}

fragment_scanner.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.myapp.camera.CameraView
        android:id="@+id/cameraPreview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

I think I have set the lifecycle correct (getting resources onResume(), releasing it onPause() roughly said) and the following works just fine:

But one thing doesn't work and that is when I press the power-button on the device and then return to the camera-preview. The result is: the preview is stuck with the image that was last captured before button was pressed. If I rotate it works fine again, since it will get through the lifecycle.

After some research I found out that this is probably due to the fact that surfaceView won't get destroyed when the power-button is pressed, i.e. SurfaceHolder.Callback.surfaceDestroyed(SurfaceHolder holder) won't be called. And in fact when I compare the (very verbose) log output of the home-button-case and the power-button-case it's the same except that 'surfaceDestroyed' won't get called.

So far I found no solution whatsoever to work around it. I purposely avoid any resource cleaning code in my surfaceDestroyed(), but this does not help. My idea was to manually destroy the surfaceView like asked in this question but this seems not possible. I also tested other applications with surfaceViews/cameras and they don't seem to have this issue. So I would appreciate any hints or tips on that.

Upvotes: 4

Views: 2897

Answers (2)

MonkeyDroid
MonkeyDroid

Reputation: 637

Just try to add

 public void onDestroy() {
 // stop decoding worker -> stop Preview -> release camera
}

as done for the onPause() cause it might be invoked as long as the pause method.

In my releaseCamera() that's what i do

    private void releaseCamera() {
    if (myCamera != null) {
        FrameLayout preview = (FrameLayout) findViewById(R.id.cameraPreview);
        preview.removeView(myPreview);
        myCamera.setPreviewCallback(null);
        myCamera.release();
        myCamera = null;

    }
}

I detach the CameraPreview (myPreview), that is what holds the current picture. And fully destroy the camera.

Upvotes: 1

Shri
Shri

Reputation: 1243

mPreview.getHolder().removeCallback(mPreview); should help?

Upvotes: 0

Related Questions