1

When I click the button in the app, it play the sound perfectly. However, the button that trigger start and stop and the back button of the phone is able to click again, but the sound keeps playing. There is no error message show up in both ellipse and the phone.

I know the problem is my program trapped in the for loop of playing the sound. However I don't know how to make it without using an infinity loop if i want to loop it infinity. Any suggestion to fix this?

The sound of this metronome is like tick, tick, tick, tock...... And I want to use the button to trigger the sound.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
    final Button button = (Button) findViewById(R.id.startStop);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            boolean start = false;
            if (start == false) {
                play();
            } else if (start == true) {
                start = false;
            }
        }
    });

}

public void play() {
    final SoundPool sndPool1 = new SoundPool(3, AudioManager.STREAM_MUSIC,
            0);
    final SoundPool sndPool2 = new SoundPool(3, AudioManager.STREAM_MUSIC,
            0);
    final int ticks = sndPool1.load(this, R.raw.tick, 1);
    final int tocks = sndPool2.load(this, R.raw.tock, 1);
    for (;;) {
        sndPool2.play(tocks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
        sndPool2.play(tocks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
        sndPool2.play(tocks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
        sndPool1.play(ticks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
    }
}
K.Hui
  • 153
  • 1
  • 13

1 Answers1

3

Your issue is that you are running an infinite loop on the UI thread. This should instead be done in a background thread. Below is an example using an AsyncTask.

public class BackgroundSound extends AsyncTask<Void, Void, Void> {

private Context context;

public BackgroundSound(Context context) {
    this.context = context;
}

@Override
protected Void doInBackground(Void... params) {

    final SoundPool sndPool1 = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
    final SoundPool sndPool2 = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
    final int ticks = sndPool1.load(context, R.raw.tick, 1);
    final int tocks = sndPool2.load(context, R.raw.tock, 1);
    for (;;) {
        sndPool2.play(tocks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
        sndPool2.play(tocks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
        sndPool2.play(tocks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
        sndPool1.play(ticks, 1f, 1f, 1, 0, 1f);
        LockSupport.parkNanos(((240000 / 200) / 4) * 1000000);
    }
}

}

And call your BackgroundSound task like this:

public class MainActivity extends Activity {

private Activity activity;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    activity = this;
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
    final Button button = (Button) findViewById(R.id.startStop);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

            new BackgroundSound(activity).execute();
        }
    });

}
}
Mike Ortiz
  • 4,031
  • 4
  • 27
  • 54
  • In the line "final int ticks = sndPool1.load(this, R.raw.tick, 1);" eclipse underlined "load". When I change it to getBaseContext, it underlined "getBaseContext()" What should I put inside? – K.Hui Jan 07 '14 at 08:49
  • Sorry about that. Inside your onClickListener, `this` no longer refers to the Activity, but instead refers to the onClickListener. If your AsyncTask is inside your Activity, then you can just set a class variable, activity, which you set in onCreate. Then, pass that into your `load()` function. – Mike Ortiz Jan 07 '14 at 09:05
  • Sorry, I don't know what you mean of set a class variable. – K.Hui Jan 07 '14 at 09:17
  • Look at the example code, where I have `private Activity activity;` This variable is not contained within any method. It's scope is greater than a single method. It is a class variable. You set the value of your class variable in onCreate with `activity = this;`. Then, because it is a class variable, this `activity` variable is still visible in your AsyncTask. – Mike Ortiz Jan 07 '14 at 09:21
  • It still underlined the "activity" in final int ticks = sndPool1.load(activity, R.raw.tick, 1); This is my project [link](https://dl.dropboxusercontent.com/u/58534378/metronome_test.zip) – K.Hui Jan 07 '14 at 09:27
  • I just updated the code. My assumption was that BackgroundSound was in your MainActivity. Since it was not, you have to pass the Context to it. My fixes are in the latest edit. – Mike Ortiz Jan 07 '14 at 09:36
  • Error message gone in eclispe, but when I run the app and click start, the app pop up error message "sorry, ...stopped " and closed my app – K.Hui Jan 07 '14 at 09:47
  • Before the line `final int ticks = sndPool1.load(context, R.raw.tick, 1);`, add the following lines: `if (sndPool1 == null) Log.d("debug", "sound pool is null"); if (context == null) Log.d("debug, "context is null");`. Run it again and let me know the output. – Mike Ortiz Jan 07 '14 at 10:07
  • I find "context is null" in the log after adding them BTW,"if (sndPool1 == null) Log.d("debug", "sound pool is null"); is dead code" [Here](https://dl.dropboxusercontent.com/u/58534378/metronome_test.zip) is the project, If you want to have a look. – K.Hui Jan 07 '14 at 10:14
  • The `activity` variable is null because it is never set. I could've sworn I set it in a previous edit, but it must not have gone through. I added the line `activity = this;` in onCreate. This should fix your problem. – Mike Ortiz Jan 07 '14 at 10:37
  • Sorry for late replay. I've just gone to work. All the problem solved.Thank you very much – K.Hui Jan 07 '14 at 16:50