My SurfaceView is not getting destroyed even if onPause of the activity is called.
I am taking care of the thread in
public void surfaceCreated(SurfaceHolder holder) {
if (mGameThread.getState() == Thread.State.TERMINATED) {
createGameThread(getHolder(), getContext());
}
mGameThread.setRunning(true);
mGameThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mGameThread.setRunning(false);
while (retry) {
try {
mGameThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
As an hack I have to check the state of the thread in onResume and if the thread is already terminated, I would finish the activity
protected void onResume() {
Log.d(mLogTag, "onResume()");
super.onResume();
if (mGameThread != null) {
if (mGameThread.getState() == Thread.State.TERMINATED) {
finish();
}
}
}
Unfortunately it is not possible to move the thread handling from surfaceDestroyed and surfaceCreated to onPause() and onResume() of the activity. Is it possible to manually destroy the SurfaceView in the onPause() and recreate it in onResume()?
You can add surface view dynamically on your view.
Example :layout.xml
<FrameLayout
android:id="#+id/fragment_file_videoplayer_surface_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
MainActivity.java
FrameLayout fl_surfaceview_container =
(FrameLayout)findViewById(R.id.fragment_file_videoplayer_surface_container);
// Add surfaceView on Framelayout
SurfaceView videoSurface = new SurfaceView(getActivity());
fl_surfaceview_container.addView(videoSurface);
//if remove or destroy surfaceview
fl_surfaceview_container.removeAllViews();
You can add a layout as a parent of the surfaceview, then set visibility of the layout GONE in onPause(), and set VISIBLE in onResume() of the activity.
Yes possible.
First initialize Size
Size currentSurfaceSize;
cameraSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(QR_Reader_Activity.this,
new String[]{Manifest.permission.CAMERA}, RequestCameraPermission);
permission = true;
return;
}
try {
cameraSource.start(cameraSurface.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
currentSurfaceSize = new Size(width, height);
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
onPause();
}
});
where do you want to destroy the surface, use this below code.
if (currentSurfaceSize==null){
cameraSurface = (SurfaceView) cameraSurface.getHolder();
cameraSurface.removeCallbacks((Runnable) cameraSurface);
}
Related
I know how to return to previous activity as usual.The current activity(VideoActivity.java) is having the SurfaceView for the MediaRecorder to record video. Whenever I implement the finish() to return to previous activity, it causing the error like logcat below:
E/BufferQueueProducer: [SurfaceView] dequeueBuffer: BufferQueue has been abandoned
E/EmulatedCamera_Preview: onNextFrameAvailable: Unable to dequeue preview window buffer: 19 -> No such device
The logcat just repeat the above 2 line and become very long list,therefore I just show this 2 line.
Besides showing the logcat above,whenever I intent to VideoActivity.java the application is stop.
This is how I implement to return to the previous activity
backButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isRecording){
stopRecording();
finish();
}else{
finish();
}
}
});
Basically I implement the SurfaceView like this:
public class VideoActivity extends AppCompatActivity implements SurfaceHolder.Callback{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
surfaceHolder = videoSurface.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
backButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isRecording){
stopRecording();
finish();
}else{
finish();
}
}
});
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try{
mCamera = Camera.open();
}catch (RuntimeException ex){
ex.printStackTrace();
}
try{
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
}catch (Exception e){
e.printStackTrace();
}
prepareRecorder();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mRecorder.reset();
mRecorder.release();
mCamera.release();
// once the objects have been released they can't be reused
mRecorder = null;
mCamera = null; }
}
This code is working fine before I return to previous activity using finish().
So my question is,if an activity having SurfaceView,how can it return to previous activity?Please show me the right way.
I realize I didnt release the Camera and MediaRecorder.I able to solve this by release the Camera and mediaRecorder before finish(),so the code is look like this
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isRecording){
Log.d("Video","stop recording");
try{
mRecorder.stop();
}catch (RuntimeException e) {
}
releaseMediaRecorder();
mCamera.lock();
isRecording = false;
releaseCamera();
finish();
}else{
releaseCamera();
finish();
}
}
});
}
private void releaseCamera(){
if (mCamera != null){
// release the camera for other applications
mCamera.setPreviewCallback(null);
surfaceHolder.removeCallback(VideoActivity.this);
mCamera.release();
mCamera = null;
}
}
private void releaseMediaRecorder(){
if (mRecorder != null) {
// clear recorder configuration
mRecorder.reset();
mRecorder.release();
mRecorder = null;
mCamera.lock();
}
}
I am using MediaPlayer and SurfaceView to stream a video from a server. The video plays fine however if the activity goes in "Paused" state, eg. when the user taps home button or recent button, On resuming the player activity the SurfaceView becomes black. I know when you leave the activity, the surfaceView is destroyed and upon resuming it is created again, so as workaround I saved the player's current position in onPause() of the activity and when the activity resumes, I seek the player to that position. This didn't work either.
So my question is how can I make the surfaceView keep the frame/picture it was displaying when the user goes out of the activity?
public class VideoPlayer extends Activity implements SurfaceHolder.Callback, OnPreparedListener {
private long PREV_PLAYER_POS;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_videoplayer);
mDecorView = getWindow().getDecorView();
mediaController = new VideoControllerView(this, mDecorView);
handler = new Handler();
Intent intent = getIntent();
usedURL = intent.getExtras().getString("vidURL");
vidID = intent.getExtras().getString("id");
mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
mProgressBar.setVisibility(ProgressBar.VISIBLE);
mContext = this;
surfView = (SurfaceView) findViewById(R.id.videoView4);
SurfaceHolder holder = surfView.getHolder();
holder.addCallback(this);
mMediaPlayer = new MediaPlayer();
mMediaPlayerControl = new VideoControllerView.MediaPlayerControl() {
……
}
mMediaPlayer.setOnPreparedListener(this);
mediaController.setOnSeekStartListener(new onSeekStartListener() {
#Override
public void onSeekStarted() {
}
});
mediaController.setMediaPlayer(mMediaPlayerControl);
mediaController.setAnchorView((ViewGroup) findViewById(R.id.container4));
mediaController.setEnabled(true);
mediaController.show();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
mMediaPlayer.setDisplay(holder);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mMediaPlayer.setDisplay(holder);
try {
mMediaPlayer.setDataSource(usedURL);
mMediaPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void onPrepared(MediaPlayer mp) {
surfView.requestLayout();
surfView.invalidate();
mMediaPlayer.start();
}
#Override
public void onSurfaceViewSizeChanged(int width, int height) {
}
#Override
protected void onResume() {
super.onResume();
mMediaPlayer.seekTo((int)PREV_PLAYER_POS);
}
#Override
public void onBackPressed() {
super.onBackPressed();
mMediaPlayer.stop();
}
#Override
protected void onPause() {
super.onPause();
PREV_PLAYER_POS = mMediaPlayer.getCurrentPosition();
mMediaPlayer.pause();
}
#Override
protected void onDestroy() {
super.onDestroy();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
Best Regards
Start your video in onResume,
#Override
protected void onResume() {
super.onResume();
mMediaPlayer.start();
mMediaPlayer.seekTo(length);
}
Hope it ll work..
The SurfaceView's surface may or may not be destroyed when you bring something up in front of the activity. See this section in the graphics architecture document for an overview. If it didn't get destroyed, then surfaceCreated() won't be called again, and your app will never call mMediaPlayer.setDisplay(holder) to connect the MediaPlayer to the surface.
I would guess that, if you brought up "recents" and then rotated the device, things would work when you returned (because the device rotation forces the surface to be recreated). You may want to add some logging to the various callbacks to see when they fire.
You will need to have a static variable that tracks whether or not the surface has been destroyed (e.g. static bool haveSurface = false, set to true in surfaceCreated(), false in surfaceDestroyed(). If it's true in onCreate(), call mMediaPlayer.setDisplay(holder) immediately.
Grafika has some examples of working with the odd SurfaceView-vs-Activity lifecycle issues, though I don't think any of them quite fit your use case.
This is my activity for a video player:
public class myActivity extends Activity
implements MediaPlayer.OnPreparedListener,
MediaController.MediaPlayerControl {
....
}
and in its onPause method I don't release the MediaPlayer and I just pause it:
#Override
protected void onPause() {
super.onPause();
lastPlaybackInfo.IsPlaying = mMediaPlayer.isPlaying();
mMediaPlayer.pause();
lastPlaybackInfo.SeekPosition = mMediaPlayer.getCurrentPosition();
}
and in onResume
#Override
protected void onResume() {
super.onResume();
if (mMediaPlayer != null) {
if (lastPlaybackInfo.IsPlaying) {
mMediaPlayer.start();
} else {
mMediaPlayer.seekTo(lastPlaybackInfo.SeekPosition);
}
mMediaController.show();
}
}
and the onTouchEvent:
#Override
public boolean onTouchEvent(MotionEvent event) {
mMediaController.show();
return true;
}
I have two problems:
The first problem is that the once the app is resumed, the MediaController which is tied to MediaPlayer is shown only one time (the call in onResume), and after that, the calls in onTouchEvent doesn't show MediaController.
The second one is that, if MediaPlayer was paused before app getting paused, after resuming the app, the SurfaceView tied to MediaPlayer is black and doesn't show the very last rendered frame.
In fact I found out if we run the code inside onResume with a delay to let the layout refresh itself, both of the problems would get resolved.
Here's how:
protected void onResume() {
super.onResume();
try {
if (IsMediaReady && IsSubtitleReady) {
if (mMediaPlayer != null) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (lastPlaybackInfo.IsPlaying) {
mMediaPlayer.start();
} else {
mMediaPlayer.seekTo(lastPlaybackInfo.SeekPosition);
}
mMediaController.show();
}
}, 100);
}
}
} catch (NullPointerException e) {
Log.e(TAG, "Exception in resume");
}
}
I've searched over and over in this forum & google about this issue, maybe it has to do something with my thread or the way how the game is starting.
This is the skeleton of the game application, please tell me what I'm doing wrong.
This is what I'm doing in thread;
public class GameThread extends Thread
{
static final long FPS = 30;
private GameView view;
private boolean running = false;
private SurfaceHolder surfaceHolder;
public boolean isSurfaceCreated = false;
private Object mPauseLock;
private boolean mPaused;
public GameThread(SurfaceHolder surfaceHolder, Handler handler, GameView view)
{
super();
mPauseLock = new Object();
mPaused = false;
this.surfaceHolder = surfaceHolder;
this.view = view;
}
public void setRunning(boolean run)
{
running = run;
}
/**
* pause thread.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* resume thread.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
#Override
public void run()
{
// run our thread on high priority to keep from getting slowdown
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
// wait for surface to become available # start
while (!isSurfaceCreated && running)
{
try {
sleep(50);
} catch (InterruptedException e) {}
}
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running){
Canvas c = null;
startTime = System.currentTimeMillis();
//long msSinceLastTick = System.currentTimeMillis() - view.lastTickMs;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder)
{
/*
* stop updating when pause is pressed
*/
if(mPaused == false)
{
view.update();
}
view.onDraw(c);
}
} finally {
if (c != null)
{
surfaceHolder.unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
This is the start activity code;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
public class test_game extends Activity {
/** Called when the activity is first created. */
private GameView Game;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Game = new GameView(this);
setContentView(Game);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
//KILL ALL
finish();
System.runFinalizersOnExit(true);
System.exit(0);
}
// ===========================================================
// onPause
// ===========================================================
protected void onPause() {
super.onPause();
}
// ===========================================================
// onStop
// ===========================================================
protected void onStop() {
super.onStop();
}
// ===========================================================
// onDestroy
// ===========================================================
#Override
protected void onDestroy() {
super.onDestroy();
}
}
Added extra lines in AndroidManifest.xml
android:launchMode="singleTask"
android:alwaysRetainTaskState="true"
GameView looks like this:
public class GameView extends SurfaceView {
private SurfaceHolder holder;
private GameThread Thread = null;
private int testVar = 0;
private boolean isPaused = false;
public GameView(Context context)
{
super(context);
loadGameFiles();
holder = getHolder();
Thread = new GameThread(holder, new Handler(), this);
holder.addCallback(new SurfaceHolder.Callback()
{
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
Thread.setRunning(false);
while (retry)
{
try {
Thread.join();
retry = false;
} catch (InterruptedException e)
{
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
Thread.isSurfaceCreated = true;
if(isPaused == true)
{
onResume();
}
Thread.setRunning(true);
Thread.start();
GameMenu();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
});
setFocusable(true);
}
public boolean isPaused()
{
return this.isPaused;
}
/**
* Pauses the physics update & animation.
*/
public void onPause() {
synchronized (holder)
{
if(isPaused == false)
{
isPaused = true;
Thread.onPause();
}
}
}
public void onResume()
{
synchronized (holder)
{
if(isPaused == true)
{
isPaused = false;
Thread.onResume();
}
}
}
etc..
Thanks for the replies, the forum commentbox doesn't let me post this; anyway, here it is:
Hi Frankenstein, I've tried what you suggested here, still doesn't work. My resume code in the GameView looks like this;
public void onResume(){ synchronized (holder)
{ if(isPaused == true){
isPaused = false; //resume notification to the gameview
Thread.onResume(); //resume the thread
}
}
}
This is on the Activity class;
#Override
protected void onPause() {
super.onPause();
Game.onPause();
}
#Override
protected void onResume() {
super.onResume();
Game.onResume();
}
I have not used logcat, not sure how to use it, I can sure call it in each steps in java but where does it displays the error/logs? thanks in advance guys!
When I resume it shows following error in LogCat;
Added this line to avoid the previous problem;
Thread.isSurfaceCreated = true;
Thread.setRunning(true);
Thread.start();
loadGame();
UPDATE:
The application returns to black screen, but it's not frozen.
Errors (updated) in logcat;
12-14 16:54:52.176: ERROR/MediaPlayerService(3937): create PVPlayer
12-14 16:55:03.172: ERROR/dalvikvm(4619): Failed to write stack traces to /data/anr/traces.txt (1093 of 3526): Unknown error: 0
12-14 16:55:03.910: ERROR/dalvikvm(25464): Failed to write stack traces to /data/anr/traces.txt (2401 of 3332): Math result not representable
12-14 16:55:03.918: ERROR/dalvikvm(25279): Failed to write stack traces to /data/anr/traces.txt (-1 of 2354): Math result not representable
12-14 16:55:32.394: ERROR/imdg81(19379): IsShutDownStarted()
12-14 16:55:32.590: ERROR/imdg81(19379): IsShutDownStarted()
12-14 16:55:37.902: ERROR/MediaPlayer(19379): error (100, 0)
12-14 16:55:37.930: ERROR/SoundPool(5264): Unable to load sample: (null)
12-14 16:55:39.281: ERROR/SoundBooster(5328): readSBTable: file open error!
12-14 16:55:39.281: ERROR/AcousticEQ(5328): [AEQ] aeqcoe.txt: file open error!
12-14 16:55:39.500: ERROR/AudioService(19379): Media server died.
12-14 16:55:39.500: ERROR/AudioService(19379): Media server started.
12-14 16:55:39.996: ERROR/MediaPlayerService(5328): create PVPlayer
In your onSurfaceCreated method you have this block of code:
if(isPaused == true){
onResume();
}
Thread.setRunning(true);
Thread.start();
your call to Thread.start() is called no matter what (even if isPaused is true). Since your thread is already started in this case, you're trying to start it twice and thus getting an illegal state exception.
Thanks guys!
I've fixed this issue, the black screen was showing because the thread isn't created again but being manipulated when I entered 2nd time to the screen. Therefore, it showed an empty/null thread being manipulated as black screen. I've added following line to OnResume()
if(!Thread.isAlive())
{
Thread = new GameThread(holder, new Handler(), this);
}
This is the fix for my issue, but now I've to implement onSaveInstanceState & onRestoreInstanceState to avoid the from re-starting from beginnig.
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.setPreviewDisplay(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()).