Reputation: 35234
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
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