I want my button to be "spammable". This means that if I tap on the button repeatedly the MediaPlayer starts all over again.
firstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (firstTextView.getText().equals("Hello world!")) {
firstTextView.setText("You clicked!");
} else {
firstTextView.setText("Hello world!");
}
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.start();
}
});
When I interrupt the MediaPlayer when it is playing, it stops and never starts again. Why?
EDIT: The problem is that I called stop(). Thanks for pointing that out.
As per the documentation, you need to re-prepare the MediaPlayer (emphasis mine):
Once in the Stopped state, playback cannot be started until
prepare() or prepareAsync() are called to set the MediaPlayer object
to the Prepared state again.
Seems you are stopping the player because you are calling mediaPlayer.stop() this makes the MediaPlayer state to go in Stopped state. It will continue to play again when you call prepare() or prepareAsync() and has its preparation callback fired to start the playing media.
Related
I have in my app a media player, to play music. When the users presses "NEXT" the next song is build and played. This all works fine until about 20-30 "NEXT" clicks the eventhandler from the media player goes haywire and keeps firing even though the event "COMPLETITION" has not occured.
Here is my function to play music:
void PlayMusic(Android.Net.Uri uri)
{
CurrentSongObject = WriteMetaDataToFileList(uri.ToString());
txt_CurrentSong.Text = CurrentSongObject.SongName;
txt_CurrentArtist.Text = CurrentSongObject.ArtistName;
if (mediaPlayer.IsPlaying)
{
mediaPlayer.Stop();
mediaPlayer = MediaPlayer.Create(this, uri);
btn_StartOrPause.SetImageResource(Resource.Drawable.btn_play);
}
else
{
mediaPlayer.Stop();
mediaPlayer = MediaPlayer.Create(this, uri);
Activity_Player.btn_StartOrPause.SetImageResource(Resource.Drawable.btn_pause);
}
if (specialMode)
{
SeekToSongMillis(uri.ToString());
}
StartMediaPlayer();
mediaPlayer.Completion += delegate
{
if (rndMode)
{
ChooseRandomNewSongAndPlay(true);
}
else
{
ChoosesNonRandomNextSongAndPlay(true);
}
};
}
So about the last part, I sign an event handler to the event of the media player having completed the playback (the song is simply over.) But after calling this function about 25 times, the event handler keeps caling and therefore auto calling the next and next and next song. Even though no song ever completes, it just keeps skipping to the next song. Am I maybe using the handler wrong?
Please help me! :)
Thanks.
EDIT:
I have noticied something else.
after the first IF I unsigned from the event (also put the event into its own function) and this fixed the issue a bit. After a while he still goes into the event, even though he shoundlt, but then immediately leave it again and continues normally. So there is still something fishy going on...
Well, turns out there is this beautiful reset property on the mediaplayer...
mediaPlayer.Stop();
mediaPlayer.Completion -= EventForMediaPlayBackCompletition;
mediaPlayer.Reset();
I start the mediaplayer to play a piece of music in a thread and I'm wondering why mediaplayer can continue working even the thread is already dead. Here is the example:
public class MusicThread extends Thread {
MediaPlayer mp;
public MusicThread(Context context) {
mp = MediaPlayer.create(context, R.raw.music);
}
#Override
public void run() {
mp.start();
Log.d("MusicThread", "mp started");
}
}
Then inside the activity:
MusicThread musicThread = new MusicThread(this);
musicThread.start();
Here is my confusion:
After musicThread.start(), the music begins. Also, the thread completes becasue we can see the log generated by Log.d(...) in LogCat and we can see the false returned by musicThread.isAlive().
I have the reference to musicThread such that it won't be GC immediately when it finishes.
But what about the mediaplayer? It continues working but the thread which it resides has died already. It seems that it's in a weird state in this case. Is it still working in musicThread? If yes, why and how? If not, where it is?
mp.start() is not a blocking call. So your thread won't wait until playing is finished. mp.start() call returns immediately. You don't even need a separate thread to call it.
PS : If you want to get a callback when the playing is finished just use setOnCompletionListener. Once the playing is completed, public void onCompletion(MediaPlayer mp) will be called
In my Activity I have the following:
private Set<MediaPlayer> mediaPlayers;
public void onSomeEventInMyActivity()
{
// play sound
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.my_sound);
mediaPlayers.add(mediaPlayer);
mediaPlayer.setOnCompletionListener(new OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mp)
{
mp.release();
mediaPlayers.remove(mp);
}
});
mediaPlayer.start();
}
#Override
protected void onStart()
{
super.onStart();
mediaPlayers = new HashSet<MediaPlayer>();
}
#Override
protected void onStop()
{
super.onStop();
for (MediaPlayer mediaPlayer : mediaPlayers)
{
if (mediaPlayer.isPlaying())
{
mediaPlayer.stop();
}
mediaPlayer.release();
}
}
Is this code sufficient or will it lead to MediaPlayer leakage? Are my implementations of onStop and onStart necessary, or can I just rely on calling release in onCompletion?
I did my code this way because I assume onStop() could be called while a MediaPlayer is playing, so I need to call release because onCompletion won't be called yet. I'm just guessing that this is right, so correct me if I am wrong.
I also read that onStop is not called in low-memory situations - what to do then?
An onStop() routine is needed if the mediaPlayer is expected to stop when the activity becomes invisible. Otherwise, the mediaPlayer goes on playing. On older OSs, Gingerbread and earlier, the activity can execute onPause() - say, when a phone call arrives - and, in extreme circumstances, be destroyed without ever executing onStop(). I don't know what would happen to a running mediaPlayer then. However, if there is a phone call coming in, it might be an idea to stop the mediaPlayer in onPause()! Later OSs always pass through onStop() before destroying the Activity. Calling mp.release() on the mediaPlayer after stopping it, in either onPause() or onStop(), is correct.
It's also desirable to remove the reference to the player held in mediaPlayers, which doesn't happen in onStop() above. Something like:
#Override public void onCompletion(MediaPlayer mp) {
mp.stop(); // It's always safe to call stop()
mp.release(); // release resources internal to the MediaPlayer
mediaPlayers.remove(mp); // remove reference to MediaPlayer to allow GC
}
and then
#Override public void onPause() {
for (Object mediaPlayer : mediaPlayers.toArray()) {
onCompletion((MediaPlayer) mediaPlayer); // stop, release, and free for GC, each mp.
}
super.onPause();
}
(I originally had for (Object mediaPlayer : mediaPlayers) {} in the above code but omfeddf345mnof32nisd45fgoq2t pointed out that I would be modifying a set while iterating over it. Thanks for the correction!)
Only callback guaranted to be called is onPause(), so you may leak this media player in some situations. In case stopping player on activity pause is not acceptable you should use service, and watch for certain events ( like incoming phone call etc )
I have created a list of songs on click on the song i am able to play the song using MedaiPlayer. While one song is playing if the user clicks another song then i am stopping the media player and starting the player again. But I am getting illegalstateexception in reset(). Here is the code where I am getting the exception. How to stop a player properly? also why am i getting this exception. How to avoid it?
public void stopPlayer() {
try {
if (player != null) {
// Log.e("Trying to Stop "," Player ");
player.stop();
player.release();
player.reset();// causes IllegalstateException
player = null;
}
} catch (Exception e) {
player = null;
playerStatus = false;
e.printStackTrace();
}
}
try this :
player.reset();
player.release();
and also have a look at media player state diagram.
If you want to play again ,then use player.reset(),
player.release() means that it releases the player object so you have to re-intialise the player. So first you use reset() and then release(). release() is used when your player object no longer working. When your activity destroys release() method to be used for good practice.
Whenever you want to stop it:
if(player!=null)
{
if(player.isPlaying())
player.stop();
player.reset();//It requires again setDataSource for player object.
}
Whenever your player no longer to be needed:
if(player!=null)
{
if(player.isPlaying())
player.stop();
player.reset();//It requires again setDataSource for player object.
player.release();
player=null; // fixed typo.
}
Though the accepted answer works, This is a better way to achieve the task
private void stopSong() {
if(mediaPlayer!=null) {
if(mediaPlayer.isPlaying()) {
mediaPlayer.reset();// It requires again setDataSource for player object.
mediaPlayer.stop();// Stop it
mediaPlayer.release();// Release it
mediaPlayer = null; // Initialize it to null so it can be used later
}
}
}
Are you planning on reusing the player again, or are you done with the player? If you're done with the player, call release() and not reset(). If you plan on reusing the player, call reset() and not release().
reset() resets the player to its uninitialized state.
release() frees all resources associated with the player.
The Media Player State Diagram shows, and also states:
Calling stop() stops playback and causes a MediaPlayer in the Started, Paused, Prepared or PlaybackCompleted state to enter the Stopped state.
Once in the Stopped state, playback cannot be started until prepare() or prepareAsync() are called to set the MediaPlayer object to the Prepared state again.
That means, that after calling stop(), we should call prepare() on the same audio file if we wish to play it again. Otherwise calling start() again won't do anything.
As prepare() might throw exception, we should wrap it in a try-catch block, like this:
public void stopAudio(View view) {
mplayer.stop();
try {
mplayer.prepare();
} catch (IOException e) {
Log.e("stopAudio", "Unable to prepare() mplayer after stop()", e);
}
}
I am working in android. I am creating a mediaPlayer which is running audio files. i have 10 buttons. i have assigned different url to each button. So when i press button1 then song of url with respect to button 1 is playing. and then i click on 2nd button then song of button 2 is also playing with song 1. but i want to stop song of button 1 when i press button 2.
this is the code i am using for this functionality:-
public void onClick(View v)
{
MediaPlayer mediaPlayer=new MediaPlayer();
if (mediaPlayer.isPlaying())
{
mediaPlayer.stop();
mediaPlayer.release();
}
int i = Integer.parseInt((v.getTag()).toString());
String str=urls[i];
try {
mediaPlayer.setDataSource(str);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (Exception e)
{
e.printStackTrace();
}
}
please check my code and let me know what is mistake done by me.
you have construct a new MediaPlayer object each time the user click you view
how could it be in the running state !!!
calling release() method on a MediaPlayer object it is in thre End state
Once the MediaPlayer object is in the End state, it can no longer be used and there is no way to bring it back to any other state.
but in case you want to reuse a MediaPlayer object you should call the
call the following method in the same order
reset()
make the mediaPlayer enter the Idle state
setDataSource()
set your data source note : the mediaplayer shoud be in the idle state
prepare()
start()