Android CameraPreview not working on return to activity
I am working on an application using the camera. I want my application to have a custom menu that launches when the user presses the menu button.
Right now the application launches properly and the CameraPreview works fine. The menu opens correctly when the menu button is pressed. It even returns to the first activity from the menu when you press the button like it is supposed to.
The problem is that the CameraPreview no longer appears in the first activity when returning from the menu activity. What do I need to do so the CameraPreview will appear properly when returning to the first activity from the menu?
public class CameraMenuTest extends Activity implements Callback {
private Camera camera;
private MediaRecorder mediaRecorder;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SurfaceView cameraPreview = (SurfaceView)findViewById(R.id.camera_preview);
SurfaceHolder holder = cameraPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_MENU ) {
Intent mIntent = new Intent(CameraMenuTest.this, CameraMenuTestMenu.class);
startActivityForResult(mIntent, 0);
return true;
}
return super.onKeyDown(keyCode, event);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mediaRecorder.setOutputFile("/sdcard/myoutputfile.mp4");
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (mediaRecorder == null) {
try {
camera = Camera.open();
camera.se开发者_StackOverflowtPreviewDisplay(holder);
camera.startPreview();
}
catch (IOException e){
Log.d("CAMERA", e.getMessage());
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
}
}
public class CameraMenuTestMenu extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
finish();
return false;
}
});
}
}
I am assuming I need to do something in the onActivityResult() of the first activity.
I have tried:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
SurfaceView cameraPreview = (SurfaceView)findViewById(R.id.camera_preview);
SurfaceHolder holder = cameraPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
and also:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
camera = Camera.open();
camera.setPreviewDisplay(holder);
camera.startPreview();
}
Thank you for your help.
Move this part of your code from onCreate() to onResume():
SurfaceView cameraPreview = (SurfaceView)findViewById(R.id.camera_preview);
SurfaceHolder holder = cameraPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Also modify the above block to this:
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.camera_preview);
SurfaceHolder holder = surfaceView.getHolder();
if ( mediaRecorder != null) {
// The activity was paused but not stopped, so the surface still exists. Therefore
// surfaceCreated() won't be called, so init the camera here.
initCamera(holder);
} else {
// Install the callback and wait for surfaceCreated() to init the camera.
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
the method initCamera(holder)
should do the same things as the overridden method surfaceCreated()
.
Don't forget to release the camera in onPause()
:
@Override
protected void onPause() {
super.onPause();
if (camera != null) {
camera.stopPreview();
camera.release();
}
}
Good Luck!
Ok, sorry I missed the hasSurface flag - it's just set and cleared when surfaceCreated()
and surfaceDestroyed()
are called.
You have two options:
Option one
Since you are using an object, mediaRecorder, you can just check whether this is null to do the same thing, like this:
mediaRecorder != null
. I've added it to the if statement above.
NOTE - if you are going to do this, you need to set mediaRecorder to null in surfaceDestroyed()
so that the above if statement works.
Option two
If you wanted to use the boolean (member variable) (hasSurface
), set it to
false
in onCreate()
,
false
in surfaceDestroyed()
true
in surfaceCreated()
eg
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
Let me know if this works for you.
Most likely reason is that when you return to your preview activity and surfaceCreated
is called again, mediaRecorder
is not null
, thus the code that is supposed to start the preview is not executed.
That's probably because the SurfaceView breaks due to onPause/onResume being called. You need to reinitialize the camera preview during these times.
From the SDK docs: Important: Call release() to release the camera for use by other applications. Applications should release the camera immediately in onPause() (and re-open() it in onResume()).
精彩评论