我的节拍器应用程序出了问题。应用程序需要在按下启动按钮时循环,并继续循环直到按下停止按钮。我尝试过使用循环调用方法,但它甚至不听按钮,因为它卡在循环中。我目前的代码是。
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
答案 0 :(得分:1)
我很确定你做错了什么是在UI线程中启动一个循环。当您在UI线程中执行全职操作时 - 您将阻止所有按钮,并且它们不再可单击。你应该做的是启动AsyncTask或FutureTask(异步实现可能更容易)并在“停止按钮”中断时取消它。在你的循环中,你必须检查Thread.getCurrentThread()。isInterrupted(),以便它可以尽快停止。
我会给你一些伪代码:
onStartClickListener{
onClick(){
//make some checks (if (value1 > 250 || value1 < 30) etc..)
myTask = new MyTask();
myTask.execute();
}
}
onStopClickListener{
onClick(){
myTask.cancel(true);
}
}
class MyTask extends AsyncTask<Void,Void,Void>{
doInBackground(){
while(true){
// WE ARE IN DIFFERENT (non UI) thread in this method
// looping and playing sound or whatever else you want
// remember you cant do UI actions here
// when you want to update UI from here you need to do a mHandler = new Handler()
// in onCreate and do mHandler.post(new Runnable()) here
if (Thread.currentThread().isInterrupted()) break;
}
}
onPostExecute(){
// use it when you want to update UI when background task was finished
}
onCancelled(){
// use it when you want to update UI when task was canceled. This is your case I think.
}
}
希望有所帮助:)
答案 1 :(得分:0)
似乎循环和事件处理程序都可能使用相同的线程,因此线程卡在循环中并拒绝放弃对事件处理程序的控制。
我的建议是在新线程中启动循环,以便让UI线程进行事件处理。如果你这样做,事件处理程序将在UI线程上处理,循环将继续在单独的线程上运行。
答案 2 :(得分:0)
您可以使用线程来执行此操作。这是一个很好的教程:
http://www.vogella.com/articles/JavaConcurrency/article.html
// create a thread to execute the metronome tick
ThreadPoolExecutor threadPoolExecutor = Executors.newSingleThreadExecutor();
Runnable makeTheMetronomeTick = new Runnable();
// add the thread to the thread pool:
Future makeTheMetronomeTickFuture = threadPoolExecutor.submit(makeTheMetronomeTick );
...
// when you want to cancel it
makeTheMetronomeTickFuture.cancel(true);