4

I am about to create simple android app to play sound on a button click but I struggle with understanding singleton design pattern which would be very helpful in this application. What I try to achieve is to have number of activities and share only one MediaPlayer instance among them so that wehen user presses the button sound plays and if he will press the same or another button on same or different activity the sound will stop.

Here is my code but after pressing the button twice another instance of MediaPlayer is created and you can here the same sound being played at the same time

public class MyMediaPlayer {
MediaPlayer mp;
private static volatile MyMediaPlayer instance = null;
private MyMediaPlayer() { }

public static MyMediaPlayer getInstance() {
    if (instance == null) {
        synchronized (MyMediaPlayer.class) {
            if (instance == null) {
                instance = new MyMediaPlayer();
            }
        }
    }

    return instance;
}
}

and MainActivity.java:

public class MainActivity extends Activity {

private MyMediaPlayer player = getInstance();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

}

public void playSound(View view){
    player.mp = MediaPlayer.create(getApplicationContext(), R.raw.sound);
    player.mp.start();
}
}

As I am not very experienced could you in addition to tips on above code explain me how can I access a field of a singleton. I am not sure if my approach is correct. If I have singleton class and I want to use this MediaPlayer instance how do I do that?

Thanks!

Lenny
  • 887
  • 1
  • 11
  • 32

2 Answers2

4

Add null check for mp object which you are creating on playSound Button click :

public void playSound(View view){
    if(player.mp==null)
      player.mp = MediaPlayer.create(getApplicationContext(), R.raw.sound);
      player.mp.start();
}

because you have created singleton class for MyMediaPlayer class which avoid creating new object when player is already available. but mp is initialized every time.

EDIT: For playing multiple sound using single MediaPlayer do it as:

if(player.mp ==null)
  player.mp = new MediaPlayer();
else
  player.mp.reset();
String fileName="android.resource://"+getPackageName()+
                                               "/"+ R.raw.sound;
player.mp.setDataSource(getApplicationContext(),Uri.parse(fileName));
player.mp.prepare();
player.mp.start();
ρяσѕρєя K
  • 132,198
  • 53
  • 198
  • 213
  • Thank you for your answer! I guess I understood how to access single MediaPlayer object correctly! This if statement `if(player.mp==null)` - could I use this even if I wouldn't create singleton class? – Lenny Feb 07 '15 at 09:48
  • @Lenny: No. because if you are using `player.mp` in multiple class's then your current implementation is ok – ρяσѕρєя K Feb 07 '15 at 09:50
  • is your solution going to play the sound only once? After I run the sound player.mp is created and if statement won't be fulfilled again – Lenny Feb 07 '15 at 09:59
  • @Lenny: let me know what you want? and my current answer is according to your question which avoid to use multiple object of `MediaPlayer` – ρяσѕρєя K Feb 07 '15 at 10:02
  • sorry if my question was not clear. I want to use single MediaPlayer object for playing multiple sounds. User will be presented with many buttons - each of this button will let him play sound but if the sound from other button is already playing pressing new button will stop previous sound and play new one. – Lenny Feb 07 '15 at 10:05
  • @Lenny: see my edit answer. now application will play all sound using single `MediaPlayer` object – ρяσѕρєя K Feb 07 '15 at 10:10
  • Works like a charm! Thanks a lot! Additionally I think that with a small tweek I could use `String fileName="android.resource://"+getPackageName()+ "/"+ R.raw.sound; player.mp.setDataSource(getApplicationContext(),Uri.parse(fileName));` to dynamically asign which sound should be played on button press, right? – Lenny Feb 07 '15 at 10:20
1
You can do this :


public class MainActivity extends Activity {



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


}

public void playSound(View view){
    MyMediaPlayer.getInstance().create(getApplicationContext(), R.raw.sound).start();

}
public void stopSound(View view){
    MyMediaPlayer.getInstance().stop();

}

}
Harsh Parikh
  • 3,845
  • 3
  • 14
  • 14
  • Thanks for you answer. I tried your code but my IDE says that there is no method `create(getApplicationContext(), R.raw.sound).start()` which there is as I am using it already! Why is that? – Lenny Feb 07 '15 at 09:55
  • In place of getApplicationContext() use MainActivity.this – Harsh Parikh Feb 07 '15 at 10:00
  • One more thing: how can I use single method to start() and stop() playing my sound with one button? – Lenny Feb 07 '15 at 10:00
  • if(MyMediaPlayer.getInstance().isPlaying()) MyMediaPlayer.getInstance().stop(); else MyMediaPlayer.getInstance().start(); – Harsh Parikh Feb 07 '15 at 10:05