Im having a problem with my metronome application. The application needs to loop when the start button is pressed, and continue to loop until the stop button is pressed. Ive tried having the loop call methods, but it doesnt even listen to the button since it is stuck in the loop. My current code is.
public class MainActivity extends Activity {
// constant
final int MINUTE = 60000;
// variables
SeekBar seekbar1, seekbar2;
EditText txtBPM1, txtBPM2;
Spinner spnTop, spnBottom;
int value1, value2;
boolean playing = false;
int tick;
int beat;
SoundPool sp;
// loop variable
int i = 0;
int tickCount = 0;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
tick = sp.load(this, R.raw.tick, 1);
beat = sp.load(this, R.raw.beat, 1);
final Spinner spnTop = (Spinner) findViewById(R.id.spnTop);
// Create an ArrayAdapter using the string array and a default spinner
// layout
ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(
this, R.array.times1, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spnTop.setAdapter(adapter1);
spnTop.setSelection(2);
final Spinner spnBottom = (Spinner) findViewById(R.id.spnBottom);
// Create an ArrayAdapter using the string array and a default spinner
// layout
ArrayAdapter<CharSequence> adapter2 = ArrayAdapter.createFromResource(
this, R.array.times2, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spnBottom.setAdapter(adapter2);
////////////////////////////////////////////////
//Seekbar/EditText//////////////////////////////
////////////////////////////////////////////////
seekbar1 = (SeekBar) findViewById(R.id.skbBPM1);
txtBPM1 = (EditText) findViewById(R.id.txtBPM1);
txtBPM1.setText("" + 120, TextView.BufferType.EDITABLE);
seekbar1.setVerticalScrollbarPosition(value1);
seekbar1.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekbar, int progress,
boolean fromUser) {
value1 = progress + 30;
txtBPM1.setText("" + value1, TextView.BufferType.EDITABLE);
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
// stops metronome if playing
i = 1;
}
@Override
public void onStopTrackingTouch(SeekBar arg0) {
// set the textbox to a new value
txtBPM1.setText("" + value1, TextView.BufferType.EDITABLE);
}
});
Button btnStart1 = (Button) findViewById(R.id.btnStart1);
btnStart1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
value1 = Integer.parseInt(txtBPM1.getText().toString());
if (value1 > 250 || value1 < 30) {
Toast.makeText(
getApplicationContext(),
"BPM value must be at least 30 and no more than 250.",
Toast.LENGTH_LONG).show();
} else {
// set frequency and timers
int tickTime = MINUTE / value1;
int n = Integer.parseInt(spnBottom.getSelectedItem()
.toString());
int beat = Integer.parseInt(spnTop.getSelectedItem()
.toString());
tickTime = (tickTime * 4) / n;
// loop to play sound every specified incriment
for (i = 0; i > 0; i += 0)
{
tickCount++;
if (tickCount == beat) {
try
{
Thread.sleep(tickTime);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
sp.play(beat, 1, 1, 0, 0, 1);
tickCount = 0;
}
else
{
try
{
Thread.sleep(tickTime);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}//end catch
sp.play(tick, 1, 1, 0, 0, 1);
tickCount++;
}//end else
}//end loop
}//end else
}
});
Button btnStop1 = (Button) findViewById(R.id.btnStop1);
btnStop1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (playing == true) {
i = 1;
} else {
Toast.makeText(
getApplicationContext(),
"Metrenome is not playing. To begin playing press the Start button.",
Toast.LENGTH_LONG).show();
}
}
});
//////////////////////////////////////////////
//Second spinner boxes/buttons////////////////
//////////////////////////////////////////////
/*
seekbar2 = (SeekBar) findViewById(R.id.skbBPM2);
txtBPM2 = (EditText) findViewById(R.id.txtBPM2);
txtBPM2.setText("" + 120, TextView.BufferType.EDITABLE);
value2 = Integer.parseInt(txtBPM2.getText().toString());
seekbar2.setVerticalScrollbarPosition(value2);
seekbar2.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekbar, int progress,
boolean fromUser) {
value2 = progress + 30;
txtBPM2.setText("" + value2, TextView.BufferType.EDITABLE);
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
// Nothing happens
}
@Override
public void onStopTrackingTouch(SeekBar arg0) {
// set the textbox to a new value
txtBPM2.setText("" + value2, TextView.BufferType.EDITABLE);
}
});
*/
}// end onCreate
}// end class
I’m pretty sure what you are doing wrong is starting a loop in UI thread. When you do a full-time action in your UI Thread – you block all buttons and they are not clickable any more. What you should do is starting AsyncTask or FutureTask (Async implementation could be easier) and cancel it with interruption on “Stop button”. In your loop you would have to check the Thread.getCurrentThread().isInterrupted() so it could stop asap.
I will give you some pseudocode:
Hope that helped 🙂