I have a button that plays an audio file on its click listener. If the button is clicked again and again while the audio file is being played then the app crashes. What's the solution?
Here is some code for reference:
private OnClickListener btnMercyListener = new OnClickListener()
{
public void onClick(View v)
{
// Toast.makeText(getBaseContext(),
// "Mercy audio file is being played",
// Toast.LENGTH_LONG).show();
if (status==true)
{
mp.stop();
mp.release();
status = false;
}
else
{
mp = MediaPlayer.create(iMEvil.this,R.raw.mercy);
//mp.start();
try{
mp.start();
status= true;
//mp.release();
}catch(NullPointerException e)
{
Log.v("MP error",e.toString());
}
}
mp.setOnCompletionListener(new OnCompletionListener(){
// #Override
public void onCompletion(MediaPlayer arg0) {
mp.release();
status = false;
}
}
);
}
};
Two things:
1. Debug the crash and see where it's failing (which line).
2. Surround the whole statement with a try/catch and simply catch an Exception.
If you have an exception or a better idea where your code is failing, then it will be much easier to give you advice on how to fix it... as a matter of fact, you might not even need advice to fix it, you might end up solving the problem by yourself and then you will reap the fruits of your own success.
Update per comments:
The documentation for MediaPlayer indicates what might be the problem given the symptoms the OP is seeing:
To stop playback, call stop(). If you wish to later replay the media, then
you must reset() and prepare() the MediaPlayer object before calling
start() again. (create() calls prepare() the first time.)
It looks like if the play button is pressed too many times, then the media may end up not being in the prepared state and thus throw some exception. The idea of disabling the play button is valid and it should take care of this situation.
Here is some illustrative code on what you want your program to do:
private OnClickListener btnMercyListener = new OnClickListener()
{
public void onClick(View v)
{
if(isPressed)
{
return;
}
isPressed = true;
// create your media player
mp = MediaPlayer.create(iMEvil.this,R.raw.mercy);
// set your listener
mp.setOnCompletionListener(mp.setOnCompletionListener(new OnCompletionListener(){
// #Override
public void onCompletion(MediaPlayer arg0) {
if(!isPressed)
{
return;
}
isPressed = false;
// re-enable your play button
playButton.enable();
// disable the pause button
pauseButton.disable();
mp.release();
mp.prepare();
}
}
);
// disable the play button
playButton.disable();
// enable the pause button
pauseButton.enable();
// start playback
mp.start();
}
};
Of course you should have the appropriate try/catch statements in there so your app doesn't crash, but this code should give you a general idea of what to do.
Related
I'm making an application with sounds that I want to loop.
The problem is that audios have a kind of fade in and fade out that every time it is played with mediaPlayer.setLooping(true); they make the loop sound very bad, because you hear it perfectly when it ends and when it starts again.
I would like to be able to play those audios from one particular second to another, for example to be able to loop from the second 00:00:04 to the second 00:00:14 and thus not hear the fade in and fade out.
At the moment I'm using this code to play the audios. Then in the button, I make the call that you see next
public void playAudio(int audioId)
{
// stop the previous playing audio
if(mMediaPlayer != null && mMediaPlayer.isPlaying())
{
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
mMediaPlayer = MediaPlayer.create(this, audioId);
mMediaPlayer.start();
mMediaPlayer.setLooping(true);
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
playAudio(R.raw.sound1);
}
});
Create a method called startPosition(int initialTime) which will seek mediaPlayer position before start() method
private void startPosition(int initialTime){
mMediaPlayer.seekTo(initialTime); //time in millisecond, e.g 4sec = 4000
}
call this method before mMediaPlayer.start() method.
Now create a thread which will run endlessly and seek your mediaplayer position back to initial on upper limit reached.
Edit
Replace your playAudio() method with the below and change upperTimerLimit with specific value e.g 14000 (14 second).
public void playAudio(int audioId)
{
// stop the previous playing audio
if(mMediaPlayer != null && mMediaPlayer.isPlaying())
{
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
mMediaPlayer = MediaPlayer.create(this, audioId);
mMediaPlayer.start();
new Thread(new Runnable() {
public void run(){
while(true){
if(mMediaPlayer.getCurrentPosition()-UpperTimeLimit >=0){ //UpperTimeLimit should be in milliseconds. UpperTimerLimit is the specific second after which player should start again the sound.
startPosition(initialTime); //Call the startPosition(int initialTime)
}
}
}).start();
}
Create the thread right after mMediaPlayer.start()
There is no need of mMediaPlayer.setLooping(true); in your playAudio() method.
Hope this will work.
I have an online music player and my problem is when user press on play button
my app freeze for 1 or 2 second(network speed).
I play music of a link of my server and put it in Voice variable and play stream that.
whats the problem of my code?
Thanks.
My code:
detail_voice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar snackbar = Snackbar.make(detail_date, " " + "دارم میگیرررررررررمش :| :)))", Snackbar.LENGTH_SHORT);
snackbar.show();
try {
mp.setDataSource(Voice);
mp.prepare();
mp.start();
detail_voice.setVisibility(View.GONE);
detail_voice_stop.setVisibility(View.VISIBLE);
} catch (IOException e) {
e.printStackTrace();
}
}
});
detail_voice_stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
detail_voice.setVisibility(View.VISIBLE);
detail_voice_stop.setVisibility(View.GONE);
mp.stop();
mp.reset();
detail_voice_stop.setVisibility(View.GONE);
}
});
The code you've provided is not extensive, but my guess is your problem might indeed have to do with loading your data over the network. Usually when loading data over a network, you'll want to do that asynchronously to avoid the program needlessly waiting for the data, and freeze during that time.
The MediaPlayer class has a prepareAsync() method which will do this for you. But, you cannot put the start() method below that anymore as it is now asynchronous. Try replacing this code:
mp.setDataSource(Voice);
mp.prepare();
mp.start();
With this:
mp.setDataSource(Voice);
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer player) {
player.start();
}
});
mp.prepareAsync();
If that code solves the problem, your connection was indeed the problem. You should not however use the setOnPreparedListener() method every time you click. I'd suggest moving it outside the onClickListener() method so it is only executed once.
This Stackoverflow question has a good implementation too. It might be worth a read as well.
I'm trying make a simple mediaplayer but the pause button doesn't work. When I click on the pause button it stops but when I click on play again it starts at the start again.
I don't know how to make one button where I can play/pause the button.
Code I currently have:
http://pastebin.com/wiDkzw5S
Thanks already!
You would need to save current position of media player and restart it later from that position using seekTo.
Something like:
int currentPos = 0;
pause.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mediaPlayer.isPlaying()) {
currentPos = mediaPlayer.getCurrentPosition();
mediaPlayer.pause();
//change image to play
} else {
mediaPlayer.seekTo(currentPos);
mediaPlayer.start();
//again revert image to pause
}
}
});
Hope it helps.
This is running test and running code, you may use this for pause and resume the media player.
int length=0;
Button pause = (Button) findViewById(R.id.pause);
pause.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
length=mediaPlayer.getCurrentPosition();
} else {
mediaPlayer.seekTo(length);
mediaPlayer.start();
}
}
});
I had a similar problem, but I couldn't get it to resume using the methods above.
I discovered my pauseAllSounds() function was pausing all MediaPlayer instances in my sound pool even if they weren't already playing. When that happened, it caused an error in each instance which wasn't playing which prevented that instance from playing again later. I discovered this after some time only by happening across the console output for my running process searching for the cause. It showed line after line of errors, revealing I was trying to pause from an invalid state.
// Make sure you test isPlaying() before pausing
public void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
position = mediaPlayer.getCurrentPosition();
}
}
Once I added the test to only pause if it was already playing, everything worked.
What i am trying to acomplish is for me to click on a button and then play a sound based on a substring.
This is my current code for pressing the button :
display.setText("start");
thefull = thef.getText().toString();
for(int a=0;a<thefull.length();a++)
{
letter=thefull.substring(a,a+1);
if(letter=="m")
{
oursong = MediaPlayer.create(MainActivity.this, R.raw.m);
oursong.start();
while(oursong.isPlaying())
{
display.setText("start");
}
oursong.release();
}
else if(letter=="a")
{
oursong = MediaPlayer.create(MainActivity.this, R.raw.a);
oursong.start();
while(oursong.isPlaying())
{
display.setText("start");
}
oursong.release();
}
display.setText("done");
but for some reason when i click my button no sound is played.
I am also new to android and java programming, so am i going right about doing this?
Because what i really want is for the program to keep checking if a sound is playing(in this case "oursound) when the button is clicked and if the sound is playing i want the program to wait for it to finish to start another sound right after it.
But for now my code doesn´t play any sounds
First of all you need to stop the media player before releasing it(its safer.)
Second, instead of using while(oursong.isPlaying())
{
display.setText("start");
} ; you have to register OnCompletionListener using setOnCompletionListener method. When the song is played endCompletion will be called. Like so;
MediaPlayer mp = new MediaPlayer();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
public void onCompletion(MediaPlayer player) {
player.release();
}});
and inside the onComplete should reset the text "done"
I have this problem, I have some audio I wish to play...
And I have two buttons for it, 'Play' and 'Stop'...
Problem is, after I press the stop button, and then press the Play button, nothing happens. -The stop button stops the song, but I want the Play button to play the song again (from the start) Here is my code:
final MediaPlayer mp = MediaPlayer.create(this, R.raw.megadeth);
And then the two public onclicks:
(For playing...)
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
button.setText("Playing!");
try {
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mp.start();
//
}
});
And for stopping the track...
final Button button2 = (Button) findViewById(R.id.cancel);
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mp.stop();
mp.reset();
}
});
Can anyone see the problem with this? If so could you please fix it... (For suggest)
Thanks alot...
James
You need to call prepare() or preparAsync() before start().
See the API for details (look at the state diagram).
There is a bug in the Android documentation, in this page it is said that you could stop() a "raw resource" mediaplayer, and then replay it just by calling reset() and prepare() before calling start() again. This doesn't work, as you have noticed.
The problem is that reset() clears the audio source and returns to the initial state, so you must set again the data source. Unfortunatelly you can't set a "raw resource" data source, because there is no API for this besides create().
I don't know a clean way of solving this issue. stealthcopter's way works great, but is a pain for your design, as you need the context for each start() call :( And involves destroying and creating a complex object, which has a price for realtime apps like games...
Another way that ensures that context will only be needed for the create() call, is to stop the media player this way:
stop()
prepare()
but if you call start() now, it won't restart from the beginning. You could call seekTo(0), but the sound will have a bit of noise from the previous play position.
I keep investigating on this. There must be a clean and efficient way of stopping and restarting the mediaplayer when created on a raw resource...
This is what I have working in my program. It releases the media player each time as I use different sounds each time it is called, however it should work as a work-around for your usage.
Creation:
public MediaPlayer mp=null;
Starting:
if (mp!=null){
mp.reset();
mp.release();
}
mp = MediaPlayer.create(test.this, soundResource);
mp.start();
Stopping:
mp.stop();
Also note that you do not require to use prepare because the create method already calls prepare for you (API REF).