How to resume MediaPlayer in Android after pressing the home button and reopen the app

fthopkins picture fthopkins · May 17, 2014 · Viewed 7.9k times · Source

I tried a lot of methods, I made a lot of changes on my code, I read Android MediaPlayer document, I tried StackOverflow examples but none of them could solve my problem.

My problem: When I press the home button of emulator or phone then reopen the app it is starting from the beginning.

Hope you can help me. Thanks in advance.

Here is my code :

public class Mediaplayer extends Activity implements OnCompletionListener,
    OnErrorListener, OnInfoListener, OnPreparedListener,
    OnSeekCompleteListener, OnVideoSizeChangedListener,
    SurfaceHolder.Callback, MediaController.MediaPlayerControl {
Display currentDisplay;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
MediaPlayer mediaPlayer;
MediaController controller;
int videoWidth = 0;
int videoHeight = 0;
boolean readyToPlay = false;
public final static String LOGTAG = "CUSTOM_VIDEO_PLAYER";

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.video);

    surfaceView = (SurfaceView) this.findViewById(R.id.SurfaceView);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setOnCompletionListener(this);
    mediaPlayer.setOnErrorListener(this);
    mediaPlayer.setOnInfoListener(this);
    mediaPlayer.setOnPreparedListener(this);
    mediaPlayer.setOnSeekCompleteListener(this);
    mediaPlayer.setOnVideoSizeChangedListener(this);
    mediaPlayer.setWakeMode(getApplicationContext(),
            PowerManager.PARTIAL_WAKE_LOCK);
    String filePath = "http://cdn.example.com/wp-content/uploads/Almost.Human-S01E10.mp4";

    try {
        mediaPlayer.setDataSource(filePath);
    } catch (IllegalArgumentException e) {
        Log.v(LOGTAG, e.getMessage());
        finish();
    } catch (IllegalStateException e) {
        Log.v(LOGTAG, e.getMessage());
        finish();
    } catch (IOException e) {
        Log.v(LOGTAG, e.getMessage());
        finish();
    }

    controller = new MediaController(this);
    currentDisplay = getWindowManager().getDefaultDisplay();

}

public void surfaceCreated(SurfaceHolder holder) {
    // Log.v(LOGTAG, "surfaceCreated Called");

    mediaPlayer.setDisplay(holder);

    try {
        mediaPlayer.prepare();
    } catch (IllegalStateException e) {
        // Log.v(LOGTAG, e.getMessage());
        finish();
    } catch (IOException e) {
        // Log.v(LOGTAG, e.getMessage());
        finish();
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    Log.v(LOGTAG, "surfaceChanged Called");
}

public void surfaceDestroyed(SurfaceHolder holder) {
    Log.v(LOGTAG, "surfaceDestroyed Called");
}

public void onCompletion(MediaPlayer mp) {
    Log.v(LOGTAG, "onCompletion Called");
    finish();
}

public boolean onError(MediaPlayer mp, int whatError, int extra) {
    Log.v(LOGTAG, "onError Called");

    if (whatError == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
        Log.v(LOGTAG, "Media Error, Server Died " + extra);
    } else if (whatError == MediaPlayer.MEDIA_ERROR_UNKNOWN) {
        Log.v(LOGTAG, "Media Error, Error Unknown " + extra);
    }

    return false;
}

public boolean onInfo(MediaPlayer mp, int whatInfo, int extra) {
    if (whatInfo == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING) {
        Log.v(LOGTAG, "Media Info, Media Info Bad Interleaving " + extra);
    } else if (whatInfo == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
        Log.v(LOGTAG, "Media Info, Media Info Not Seekable " + extra);
    } else if (whatInfo == MediaPlayer.MEDIA_INFO_UNKNOWN) {
        Log.v(LOGTAG, "Media Info, Media Info Unknown " + extra);
    } else if (whatInfo == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
        Log.v(LOGTAG, "MediaInfo, Media Info Video Track Lagging " + extra);
        /*
         * Android Version 2.0 and Higher } else if (whatInfo ==
         * MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
         * Log.v(LOGTAG,"MediaInfo, Media Info Metadata Update " + extra);
         */
    }
    return false;
}

public void onPrepared(MediaPlayer mp) {
    Log.v(LOGTAG, "onPrepared Called");
    videoWidth = mp.getVideoWidth();
    videoHeight = mp.getVideoHeight();

    if (videoWidth > currentDisplay.getWidth()
            || videoHeight > currentDisplay.getHeight()) {
        float heightRatio = (float) videoHeight
                / (float) currentDisplay.getHeight();
        float widthRatio = (float) videoWidth
                / (float) currentDisplay.getWidth();

        if (heightRatio > 1 || widthRatio > 1) {
            if (heightRatio > widthRatio) {
                videoHeight = (int) Math.ceil((float) videoHeight
                        / (float) heightRatio);
                videoWidth = (int) Math.ceil((float) videoWidth
                        / (float) heightRatio);
            } else {
                videoHeight = (int) Math.ceil((float) videoHeight
                        / (float) widthRatio);
                videoWidth = (int) Math.ceil((float) videoWidth
                        / (float) widthRatio);
            }
        }
    }

    surfaceView.setLayoutParams(new LinearLayout.LayoutParams(videoWidth,
            videoHeight));
    mp.start();

    controller.setMediaPlayer(this);
    controller.setAnchorView(this.findViewById(R.id.MainView));
    controller.setEnabled(true);
    controller.show();
}

@Override
protected void onPause() {
    super.onPause();
    if (mediaPlayer.isPlaying()) {
        mediaPlayer.pause();
    } else {
        return;
    }
}

public void onSeekComplete(MediaPlayer mp) {
    Log.v(LOGTAG, "onSeekComplete Called");
}

public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
    Log.v(LOGTAG, "onVideoSizeChanged Called");
}

public boolean canPause() {
    return true;
}

public boolean canSeekBackward() {
    return true;
}

public boolean canSeekForward() {
    return true;
}

public int getBufferPercentage() {
    return 0;
}

public int getCurrentPosition() {
    return mediaPlayer.getCurrentPosition();
}

public int getDuration() {
    return mediaPlayer.getDuration();
}

public boolean isPlaying() {
    return mediaPlayer.isPlaying();
}

public void pause() {

    mediaPlayer.pause();

}

public void seekTo(int pos) {
    mediaPlayer.seekTo(pos);
}

public void start() {
    mediaPlayer.start();
}

@Override
public boolean onTouchEvent(MotionEvent ev) {

    controller.show();

    return false;
}

@Override
public int getAudioSessionId() {
    // TODO Auto-generated method stub
    return 0;
}

 }

Answer

Squonk picture Squonk · May 18, 2014

I understand you have accepted an answer but I'll explain what the problem was based on your comments on your question and the comments from you and Nana on Nana's answer.

  1. A SurfaceView is destroyed when it is no longer visible and recreated when it becomes visible again.
  2. You are calling mp.pause() in your Activity onPause() method.
  3. When you go to the 'recent' apps list and attempt to restart the app, the SurfaceView is recreated.
  4. In surfaceCreated method you are calling mp.prepare() but at this point mp is in a paused state and calling prepare() on a paused Mediaplayer will throw an IllegalStateException.
  5. You have a try / catch block which catches IllegalStateException and calls finish() - this is why the first attempt to restart the app from the 'recent' list causes the the Activity to be destroyed.
  6. As a result of the above sequence of events you need a second attempt to re-open the app from the 'recent' list but as the Activity has been destroyed it will go through a full creation (with onCreate(..) being called. This is why it starts from the beginning.

The answer from Nana is a workaround but it will still mean having to use two attempts to restart your Activity from the 'recent' list.

Unfortunately the MediaPlayer class is lacking in methods for checking the 'state' with isPlaying being the only useful method for any state. It's a shame the class devs didn't think to add a getState() method (or similar) to allow checking for whether it's started, playing, stopped, paused etc.

One way of preventing the IllegalStateException would be to have a boolean called isPaused (for example) then modify your Activity onPause() as follows...

if (mediaPlayer.isPlaying()) {
    mediaPlayer.pause();
    isPaused = true;
}

...and in surfaceCreated(...)...

try {
    if (isPaused) {
        mpStart();
        isPaused = false;
    }
    else
        mediaPlayer.prepare();
}
// catch blocks here