I want to play songs one after another in my music player app. I checked this question but my music player plays the next song only once. After that it stops. For example, it's playing Song A, then it'll play next Song B, but after song B it won't play Song C.
Here is my code:
OnCompleteListener:
//mp is MediaPlayer object, al is ArrayList of songs and their ids(R.raw.song), song_no is the index of the song in al
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
song_no = (song_no +1) % al.size();
playSong();
}
});
I have the same code for "next" button which works perfectly, even after reaching the end of list it loops back.
playSong function:
public void playSong()
{
song = Uri.parse("android.resource://" + getPackageName() + "/" + al.get(song_no).id());
try
{
mp.stop();
mp.reset();
mp.release();
mp = null;
}
catch(Exception e)
{
Log.d("playSong", e.toString();
}
mp = MediaPlayer.create(getApplicationContext(), song);
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
}
I tried removing mp.reset(), mp.release() and mp = null but it still played the next song only once.
It looks like you want a Queue data structure, hopefully is gonna be easier to handle than keeping track of indexes.
Your al variable would store a queue of songs to play, in your onCompletion method you can call a playNextSong() method that handles the queue using poll() or remove() to get the next song and play until the queue is empty.
If you want to keep your ArrayList, Try debugging your song_no and song variables to narrow down if the problem is in the song order logic or the MediaPlayer usage.
Related
I have 8 audio files that I need to play when a button is pressed.
Currently, these files are played using a class. In this class, each audio file has it's own function that plays and pauses each audio file.
Is there a way to do this without repeating the same function for different audio files?
The button in question is connected to an Adafruit feather - essentially if the button is pressed the phone knows to play whichever audio is required.
Here's some code:
Here's what I have so far:
public class Audio {
MediaPlayer mp;
boolean paused = false;
public void playSound_1(Context context) {
mp = MediaPlayer.create(context, R.raw.Sound_1);
mp.start();
}
public void playSound_2(Context context) {
mp = MediaPlayer.create(context, R.raw.Sound_2);
mp.start();
}
public void playSound_3(Context context) {
mp = MediaPlayer.create(context, R.raw.Sound_3);
mp.start();
}
}
In my fragment I then call the function for each sound:
if (data_check.contains("Sound_1"){
audio.playSound_1(this.getContext());
}
else if (data_check.contains("Sound_2"){
audio.playSound_2(this.getContext());
}
The current results are that if the button is pressed (and data_check finds the name of the Sound) that sound plays.
What I'd like to do is have the same results but without having public void playSound_1, 2, 3, 4... etc.
In a situation where I have a listview that in each list item when clicking is an audio and is played when clicked on the desired item.
When you click on multiple items, the audio blends.
I would like to know how I can click on an item and play and if I want another item, when clicking it the previous audio stops and the audio of the clicaco item starts.
I tried to use the code below, but audios do not stop when I click on another item.
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mediaPlayer = MediaPlayer.create(MainActivity.this, caminhoAudio[position]);
if ( !(mediaPlayer.isPlaying()) )
{
tocarSom();
}
}
});
}
public void tocarSom() {
if (mediaPlayer != null)
{
mediaPlayer.start();
}
// LIBERAR MEMÓRIA
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
};
});
}
Thank You!!!
Well, if your methode startAudio() automatically do everything needed to start to play a song, you have to call startAudio() after the mediaPlayer.release();
Do something like this.
if(mMediaPlayer!=null)
{
mMediaPlayer.release();
mMediaPlayer=null;
}
if(mMediaPlayer != null) {
//Fist stop the current playing raw file
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
//Then Play the selected raw file.
tocarSom();
} else {
//If nothing is playing then Play the selected raw file or audio
tocarSom();
}
I am making a sound board app. I have a String List of sound descriptions that populate the listView. My onItemClick takes in a switch statement that assigns each sound to it's string description from the list. The sounds work when the list item is clicked, but after so many clicks, all the sounds stop. the switch statement looks like this in my ItemOnClick:
switch (soundName){
case "magic whoosh":
mediaPlayer = MediaPlayer.create(context, R.raw.magic_whoosh);
mediaPlayer.start();
break;
case "magic poof":
mediaPlayer = MediaPlayer.create(context, R.raw.magic_poof);
mediaPlayer.start();
break;
}
As requested a possible answer;
//declare instance variable
static MediaPlayer mediaPlayer;
//handle listview on item click
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(mediaPlayer==null){
mediaPlayer=new MediaPlayer();
try{
mediaPlayer.setDataSource(//datasource based on position);
mediaPlayer.prepare(); //this uses the same UI thread
mediaPlayer.start();
}catch(Throwable e){
//handle possible errors
}
}else{
if(mediaPlayer.isPlaying())mediaPlayer.stop();
mediaPlayer.reset();
try{
mediaPlayer.setDataSource(//datasource based on position);
mediaPlayer.prepare(); //this uses the same UI thread
mediaPlayer.start();
}catch(Throwable e){
//handle possible errors
}
}
}
});
I want MediaPlayer to take in an arraylist of songTitles and have it check which song title came in, then play that song. When it finishes, I then want it to go to the next song title in the loop and play that one. However, my code only plays the last song.
public void play(Context c, ArrayList<String> songTitles) {
stop();
for (String song: songTitles){
if (song.equalsIgnoreCase("shakeItOff")){
mSongPlayer = MediaPlayer.create(c, R.raw.shaketoff);
} else if (song.equalsIgnoreCase("dropItLow")){
mSongPlayer = MediaPlayer.create(c, R.raw.dropitlow);
} else if (song.equalsIgnoreCase("chachaslide")){
mSongPlayer = MediaPlayer.create(c, R.raw.chachaslide);
}
mSongPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
if (mp == mSongPlayer) {
mSongPlayer.start();
}
}
});
mSongPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
stop();
}
});
}
}
You need to use the MediaPlayer.OnCompletionListener to start the new track when the previous one finishes, so you could do something more like the following (I haven't compiled it, so there may be some syntax errors):
public void play(final Context c, ArrayList<String> songTitles) {
stop();
if (songTitles != null && songTitles.size > 0) {
final List<String> playList = new ArrayList<String>(songTitles);
String song = playList.get(0);
playList.remove(0);
mSongPlayer = MediaPlayer.create(c, getSongResourceId(song));
mSongPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
if (mp == mSongPlayer) {
mSongPlayer.start();
}
}
});
mSongPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
stop();
// Recursively call the play() method with one less
// track in the list.
play(c, playList);
}
});
}
}
public int getSongResourceId(String songTitle) {
if (song.equalsIgnoreCase("shakeItOff")){
return R.raw.shaketoff;
} else if (song.equalsIgnoreCase("dropItLow")){
return R.raw.dropitlow;
} else if (song.equalsIgnoreCase("chachaslide")){
return R.raw.chachaslide;
}
}
The first time through, this plays the first track in the list, then in the MediaPlayer.OnCompletionListener, it recursively calls the play() method with a copy of the list that has had the first track removed from it. This means each time play() is called, the list is shorter until we reach the end of the list.
I'm not sure if there is a way to do it only using a single MediaPlayer.
But, I'm sure that your are only playing the last song due to the follow:
Every time you create the MediaPlayer, you are overriding the previously one, so if your first MediaPlayer is for "shakeItOff", the next is for "dropItDown", when you reach your last one, the "chachaslide", you end up referencing a MediaPlayer that will play chachaslide.
Every time you go through the loop you are overriding the last OnCompletionListener that you attached before. So, you end with the last listener that you attached (your last song)
You are asserting the prepared MediaPlayer to the current MediaPlayer, so even if you manage to prepare every MediaPlayer to play, you will only play the currentOne, as for 1 is "chachaslide".
You can check the lifecycle of the MediaPlayer here: http://developer.android.com/reference/android/media/MediaPlayer.html
So, the only way you can reuse the same MediaPlayer reference is to manage it for yourself, other way you end with at least 3 instances at memory of the MediaPlayer
I have a few media players setup to play one after another on a button click however there is a noticeable gap between the media players playing ie. once mediaplayer one has finished there is a half a second before mediaplayer two plays, for the purpose I'm using the mediaplayers for the gap in audio is very noticeable, so what I'm asking is, is there a way to remove this gap. Now I don't know if I'm going wrong using different mediaplayers each time however this is what I've come up with so far.
Basically I've got onCompleteionListeners for each mediaplayer and within those I have the next mediaplayer play until the last. Any pointers would be appreciated.
public void onClick(View v) {
mpButtonThree = MediaPlayer.create(MainActivity.this, R.raw.audioReplay);
if (mpButtonThree==null){
//display a Toast message here
return;
}
mpButtonThree.start();
mpButtonThree.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mpButtonThree) {
mpButtonThree.release();
mpButtonOne = MediaPlayer.create(MainActivity.this, audioReplayPrimary);
if (mpButtonOne==null){
//display a Toast message here
return;
}
mpButtonOne.start();
mpButtonOne.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mpButtonOne) {
mpButtonOne.release();
mpButtonTwo = MediaPlayer.create(MainActivity.this, audioReplaySecondary);
if (mpButtonTwo==null){
//display a Toast message here
return;
}
mpButtonTwo.start();
mpButtonTwo.setOnCompletionListener(new soundListener1()
{
});
}
If You play files in series you can use single media player object.
create function that plays next media file and put it into OnCompletion.
This should remove gap between playing, because You don't have to release and create media player every time