22

I'm having issues with Android's MediaPlayer. It seems like it's missing important functionality, mainly a way to get the current status of MediaPlayer or to find out if it's prepared. I know there's the on prepared listener, but the MediaPlayer lasts longer than the Activity, so when the Playing Activity is resumed, it would be nice to get current player state, whether or not it's trying to load media, whether media is loaded, etc. Am I missing something, or do I have to keep track of the player states myself?

Other functionality that would be nice would be onPlayStateChanged() - I currently have to keep track play state manually. Am I doing it wrong?

LittleBobbyTables - Au Revoir
  • 32,008
  • 25
  • 109
  • 114
StackOverflowed
  • 5,854
  • 9
  • 55
  • 119

6 Answers6

19

Hope it's not too late for an answer. The MediaPlayer class has no such thing as an isPrepared() or a getStatus() method, and you have to keep track of its state yourself. However, that's not that difficult.

The MediaPlayer class has a good state diagram that really helps. You should implement your service based on that diagram. Also, if you always control the MediaPlayer object from the same thread, it's easy to keep track of its state, so I recommend you to do that. The prepareAsync() method is the only asynchronous method that you have to take care of, but you could keep a boolean that indicates that the player is being prepared, which would be 'true' from the prepareAsync() call until onPrepared() is called. Anyway, you can always implement onError and catch the IllegalStateException to avoid crashes if you accidentally call any method from a illegal state.

Nonetheless, the media playback guide helped me a lot.

Alex Machado
  • 1,171
  • 1
  • 12
  • 22
  • 22
    Marking this as the Accepted Answer. The sad reality is that Android for media playback/consumption is really lacking and even basic functionality like state retrieval is missing. The best way around it is for you to write a wrapper around the MediaPlayer object and store state yourself. – StackOverflowed Apr 04 '14 at 23:06
  • 13
    Just ran into this problem myself. Such a ridiculous oversight given how sensitive its methods are to current state. – sleep Aug 13 '15 at 12:18
  • 1
    At least they could do "No Operation" instead of throwing brutal `IllegalStateException` in state machine – Jemshit Jul 04 '19 at 11:33
11

I needed to see the status while debugging to troubleshoot a problem, so I just placed this code somewhere after I knew the MediaPlayer had been prepared:

try {
    this.audioPlayer.prepare();
} catch (Exception e) {
}

That prints an error to the console like "E/MediaPlayer﹕ prepareAsync called in state 32."

Now if I could just find a place where all the status codes are listed...

arlomedia
  • 8,534
  • 5
  • 60
  • 108
  • That code may throw an exception if in the wrong state; but it is designed to actually start a new state - which in most of cases IT IS NOT what you want. – Gogu CelMare Sep 06 '20 at 23:36
  • According to the MediaPlayer documentation (https://developer.android.com/reference/android/media/MediaPlayer#StateDiagram), prepare() will throw an exception if called in any state but the Initialized state. So my suggestion to use this after you know the MediaPlayer has been prepared should work reliably. – arlomedia Sep 07 '20 at 18:34
3

I have found something which might be helpful for you and others. There is a setOnPreparedListener() function in MediaPlayer class which makes you able to run a piece of code when the MediaPlayer is prepared.

Also, if you want to be sure your media has been loaded, you can use the getDuration() function. This code returns the duration in milliseconds, if no duration is available it returns -1. Here below is the code:

yourMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        if(yourMediaPlayer.getDuration() != -1){
            //your code when when something is loading
        }
    }
}
toshiro92
  • 1,287
  • 5
  • 28
  • 42
  • This answer is wrong because `getDuration` can only be called once the `onPrepared()` is called. Otherwise it throws IllegalStateException – Gunhan May 05 '23 at 10:21
2

There is no getState of MediaPlayer class, but internally it has a state, as explained by alex.magellan. Calling methods at "not allowed states" results in Exception.

To avoid these, i have created a StateMachine with MediaPlayerWrapper class. So instead of calling MediaPlayer directly, MediaPlayerWrapper is used, which internally updates StateMachine and exposes getState() method.

StateMachine and Wrapper class implementations can be found here.

Jemshit
  • 9,501
  • 5
  • 69
  • 106
0

I don't think there's a way to do it through the MediaPlayer class itself.

Easiest thing to do is global variable that gets set to true upon creation and reset. It get set to false on release.

boolean playerAvailable = true;

mediaPlayer = MediaPlayer.create(myContext, soundId); // ready to play

playerAvailable = true;

....

mediaPlayer.reset();   // ready to play again

playerAvailable = true;

....

mediaPlayer.release(); // can't be played until release.

playerAvailable = false;
0

you could make a workaround for this by having a predefined boolean variable and setting it to true when the onPrepared() callback is called and set it to false when the MediaPlayer starts. for example:

public boolean mpPrepared = false;

mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        mpPrepared = true;
    }
});

mp.start();
mpPrepared = false;
harveyhans
  • 459
  • 6
  • 12