Challenge solution for Pausing Audio Playback


#1

My solution for the playback , the play button act like a pause if the media is playing.

[code]public class AudioPlayer {

private MediaPlayer mPlayer;

public void stop() {
	if (mPlayer != null) {
		mPlayer.release();
		mPlayer = null;
	}
}

public void play(Context c) {
	if (mPlayer == null){
		stop();
		mPlayer = MediaPlayer.create(c, R.raw.one_small_step);

		mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

			@Override
			public void onCompletion(MediaPlayer mp) {
				stop();
			}
		});
		mPlayer.start();
	} else if (mPlayer.isPlaying()) {
		mPlayer.pause();
	} else {
		
		mPlayer.start();
	}
}

}[/code]


#2

You are calling stop() if the mPlayer == null, which does nothing, since the stop() function requires it to NOT be null. Where you really need it is in your last else clause before calling start().


#3

Here’s my attempt at the solution. I’ve created a new Pause button and its OnClickListener calls AudioPlayer.pause():

	public void pause() {
		if (mPlayer != null) {
			if (mPlayer.isPlaying()) mPlayer.pause();
			else mPlayer.start();
		}
	}

This works fine, but I had a question. The documentation for MediaPlayer says:

So theoretically I could press the Pause button twice in rapid succession expecting that the audio would be paused and resumed, but if that second button press came before the state had changed to Started, this code would call MediaPlayer.pause() twice. This would seem to me to be a very unlikely case (we’re not streaming video here) and I haven’t been able to produce this effect myself, but I’d rather ask than assume. Would it be safer to create a boolean isPaused and toggle it in the AudioPlayer.pause() method and set it to false in the AudioPlayer.play() method?


#4

The case you describe is for streaming audio, like a podcast. Implementing the UI for that is more challenging than what we do in this chapter. If you’re doing that, I recommend studying the state diagram in the MediaPlayer reference docs very closely. You will want to write code that detects when the state of the MediaPlayer changes, and then updates the controls to reflect which operations are valid in each state.


#5

Here’s my solution. I took out the stop() at the beginning of the play(Context c) method and used checked to see mPlayer was null instead. Is this OK to do?

[code] public void pause(){
if(mPlayer != null && mPlayer.isPlaying()){
mPlayer.pause();
}
}

public void play(Context c){

	if (mPlayer == null){
		
		mPlayer = MediaPlayer.create(c, R.raw.one_small_step);
		mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
		
		@Override
			public void onCompletion(MediaPlayer mp) {
				stop();
			}
		});
	}
	mPlayer.start();
}

}[/code]


#6

Sure!


#7

Here’s my solution. I decided to still have 2 buttons, but I just change the text on the Play button to “Pause” when the music is paused, and back again to “Play” to resume the playback:

HelloMoonFragment.java:

mPlayButton = (Button) v.findViewById(R.id.helloMoon_playButton);
mPlayButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // plays the sound
        if (mPlayButton.getText().equals("Play")) {
            mPlayer.play(getActivity());
            mPlayButton.setText("Pause");
        }
        // pauses the sound
        else if (mPlayButton.getText().equals("Pause")) {
            mPlayer.pause();
            mPlayButton.setText("Play");
        }
    }
});

In AudioPlayer.java

public class AudioPlayer {
    private MediaPlayer mPlayer;
    private int position = 0;

    // releases mediaplayer once done with it
    public void stop() {
        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }

    // pauses the mediaplayer and gets it's current postion so you can resume it afterwards
    public void pause() {
        mPlayer.pause();
        position = mPlayer.getCurrentPosition();
    }

    public void play(Context c) {
        stop();

        mPlayer = MediaPlayer.create(c, R.raw.one_small_step);

        // stops the MediaPlayer once the song is done
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                stop();
            }
        });

        // starts the mediaplayer and resumes it from where it left off.
        mPlayer.seekTo(position);
        mPlayer.start();

    }
}

#8

Liked your implementation.
I just added some code to manage the Play/Pause button text in case the user clicks on Stop while Playing (i.e. Pause text being displayed, should be reverted back to Play).


#9

I would expect the stop button to reset the position of the playback to 0 otherwise how is it different than the pause button?


#10

My solution looks a bit more complicated than the others.
First I created a pause button in fragment_hello_moon.xml and wired it up in HelloMoonFragment.java
Next I made private fields to save the position of the player (int), and check whether or not the pause method was called (boolean).
Finally I modified and created some methods as you can see here:

...
public void stop() {
		if (mPlayer != null) {
			mPausePushed = false;
			mPosition = 0;
			mPlayer.release();
			mPlayer = null;
		}
	}
	
	public void pause() {
		if (mPlayer.isPlaying()) {
			mPosition = mPlayer.getCurrentPosition();
			mPausePushed = true;
			mPlayer.pause();
		}
	}
	
	public void play(Context c) {
		if (!mPausePushed) {
			stop();
		} 
		
		if (mPlayer != null) {
			mPlayer.seekTo(mPosition);
			mPlayer.start();
		} else {
			mPlayer = MediaPlayer.create(c, R.raw.one_small_step);
			mPlayer.start();
		}
...

Despite this verbosity, everything works well and as expected!


#11

This is my answer…
Declare currrent position initially then the following :slight_smile:

public void pause()
{
currentposition = mPlayer.getCurrentPosition();
if(mPlayer.isPlaying())
{
mPlayer.pause();
}
else
{
mPlayer.start();
}
}


#12

I did this and worked. It’s simple and maybe it can helps someone.

I added this code at AudioPlayer.java

public void pause() {
		
		mCurrentPosition = mPlayer.getCurrentPosition();
		mPlayer.pause();
}

and also I changed the play method to this:

public void play(Context c) {
		stop();
		
		mPlayer = MediaPlayer.create(c,R.raw.one_small_step);
		
		mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
			public void onCompletion(MediaPlayer mp) {
			stop();
			}
		});
		
		if(mCurrentPosition != 0) {
			mPlayer.seekTo(mCurrentPosition);
		}
		
		mPlayer.start();
}

Finally I added in the beginning of the class

private int mCurrentPosition;

#13

Here is my solution:

package com.bignerdranch.android.hellomoon;

import android.content.Context;
import android.media.MediaPlayer;

public class AudioPlayer {

	private MediaPlayer mPlayer;

	private boolean paused = false;

	public void stop() {
		if (mPlayer != null) {
			mPlayer.release();
			mPlayer = null;
		}
	}

	public void play(Context c) {

		if (!paused || mPlayer == null) {
			stop();

			mPlayer = MediaPlayer.create(c, R.raw.one_small_step);
			mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

				@Override
				public void onCompletion(MediaPlayer mp) {
					stop();
				}
			});

			mPlayer.start();
		} else {
			mPlayer.start();
			paused = false;
		}

	}

	public void pause() {
		if (mPlayer != null) {
			mPlayer.pause();
			paused = true;
		}
	}

}

#14

I did something very similar to jmrmbz where I had my button text change from Play to Pause and vice versa. However, I discovered when I got to the Localization chapter the mPlayButton.getText() and .setText() will not convert to Spanish because the text comes from the fragment_hello_moon.xml file. Using @string reference with the .getText() and set.Text() do not work. I think I’ve created a new challenge for myself to take on for this chapter!

[quote=“jmrmbz”]Here’s my solution. I decided to still have 2 buttons, but I just change the text on the Play button to “Pause” when the music is paused, and back again to “Play” to resume the playback:

HelloMoonFragment.java:

mPlayButton = (Button) v.findViewById(R.id.helloMoon_playButton);
mPlayButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // plays the sound
        if (mPlayButton.getText().equals("Play")) {
            mPlayer.play(getActivity());
            mPlayButton.setText("Pause");
        }
        // pauses the sound
        else if (mPlayButton.getText().equals("Pause")) {
            mPlayer.pause();
            mPlayButton.setText("Play");
        }
    }
});

In AudioPlayer.java

[code]
public class AudioPlayer {
private MediaPlayer mPlayer;
private int position = 0;

// releases mediaplayer once done with it
public void stop() {
    if (mPlayer != null) {
        mPlayer.release();
        mPlayer = null;
    }
}

// pauses the mediaplayer and gets it's current postion so you can resume it afterwards
public void pause() {
    mPlayer.pause();
    position = mPlayer.getCurrentPosition();
}

public void play(Context c) {
    stop();

    mPlayer = MediaPlayer.create(c, R.raw.one_small_step);

    // stops the MediaPlayer once the song is done
    mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            stop();
        }
    });

    // starts the mediaplayer and resumes it from where it left off.
    mPlayer.seekTo(position);
    mPlayer.start();

}

}
[/code][/quote]


#15

Only after reading the challenge again did i realize that what i did wasn’t necessary, as i thought it asked for a pause button that pauses the audio. so here is my solution.

  1. I created a new pause button in fragment_hello_moon.xml

<Button android:id="@+id/hellomoon_pauseButton" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="@string/hellomoon_pause" />

  1. I added a method in AudioPlayer.java to pause the audio by first checking to see if any audio was playing before pausing, and resuming playback by pressing the pause button again

public void pausing() { if (mPlayer.isPlaying()) mPlayer.pause(); else mPlayer.start();

  1. I declared a button in HelloMoonFragment, named it mPauseButton, hard-wired the new pause button, set a listener and added the pausing method.

[code]mPauseButton = (Button) v.findViewById(R.id.hellomoon_pauseButton);
mPauseButton.setOnClickListener(new View.OnClickListener() {

		@Override
		public void onClick(View v) {
			mPlayer.pausing();
			
		}
	});[/code]

Ofcourse, the pause button wasn’t necessary, but i’ve taken this as a learning lesson :smiley:


#16

I went with the similar approach, but you need to check if mPlayer is instantiated. Otherwise, pause button will crash the app if it’s clicked before play button.

[code] public void pause() {
if (mPlayer == null)
return;

	if (mPlayer.isPlaying())
		mPlayer.pause();
	else
		mPlayer.start();
}[/code]