Android测验游戏 – 每个qstion的倒数计时器

我使用以下教程为Android创建了一个Quiz应用程序: http : //automateddeveloper.blogspot.co.uk/2011/06/getting-started-complete-android-app.html

对于每个问题,用户只有20秒的时间来回答它。 如果他/她在20秒内未能回答,则会弹出AlertDialog ,游戏将终止。

为此,我在QuestionActivity classOnCreate方法中添加了一个计数器:

 final TextView myCounter = (TextView) findViewById(R.id.countdown); new CountDownTimer(20000, 1000) { @Override public void onFinish() { timeUp(); } @Override public void onTick(long millisUntilFinished) { myCounter.setText("Time left: " + String.valueOf(millisUntilFinished / 1000)); } }.start(); public void timeUp() { AlertDialog.Builder builder = new AlertDialog.Builder( QuestionActivity.this); builder.setTitle("Times up!") .setMessage("Game over") .setCancelable(false) .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { QuestionActivity.this.finish(); } }); AlertDialog alert = builder.create(); alert.show(); } 

计数器正常显示和function在屏幕上。 在回答问题后,活动转到下一个问题,计数器再次重置为20秒。

问题

测验有15个问题,在回答3或4个问题后,应用程序崩溃,我收到以下错误:

 07-18 00:49:05.530: E/AndroidRuntime(4867): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@41533a80 is not valid; is your activity running? 

我相信这与AlertDialog 。 我在Stackoverflow上查找了这个错误代码,流行的解决方案是在构建AlertDialog时将ActivityName.this作为上下文AlertDialog

不幸的是,这并没有解决问题。

我相信计数器为整个活动设置了20秒的时间限制。 我的要求是每个问题20秒。

但是,当用户按下“ Next按钮并且活动移至下一个问题时,计数器将重置为20秒。

当用户按下“ Next按钮时,我应该重置计数器吗? 这是Next按钮的OnClickListener代码

 if (currentGame.isGameOver()) { Intent i = new Intent(this, EndgameActivity.class); startActivity(i); finish(); } else { Intent i = new Intent(this, QuestionActivity.class); startActivity(i); SHOULD I ADD SOMETHING HERE? finish(); 

谁能帮我编码解决问题的方法?

这是QuestionActivity.class所有代码

 public class QuestionActivity extends SherlockActivity implements OnClickListener { private Question currentQ; private GamePlay currentGame; private Context context; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.question); getSupportActionBar().hide(); /** * Configure current game and get question */ currentGame = ((ChuckApplication) getApplication()).getCurrentGame(); currentQ = currentGame.getNextQuestion(); Button nextBtn = (Button) findViewById(R.id.nextBtn); nextBtn.setOnClickListener(this); Button quitBtn = (Button) findViewById(R.id.quitBtn); quitBtn.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { finish(); } }); //Update the question and answer options.. setQuestions(); final TextView myCounter = (TextView) findViewById(R.id.countdown); new CountDownTimer(20000, 1000) { @Override public void onFinish() { // myCounter.setText("Time up!"); timeUp(context); } @Override public void onTick(long millisUntilFinished) { myCounter.setText("Time left: " + String.valueOf(millisUntilFinished / 1000)); } }.start(); } public void timeUp(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder( QuestionActivity.this); builder.setTitle("Times up!") .setMessage("Game over") .setCancelable(false) .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { QuestionActivity.this.finish(); } }); AlertDialog alert = builder.create(); alert.show(); } /** * Method to set the text for the question and answers from the current * games current question */ private void setQuestions() { // set the question text from current question String question = Utility.capitalise(currentQ.getQuestion()) + "?"; TextView qText = (TextView) findViewById(R.id.question); qText.setText(question); // set the available options List answers = currentQ.getQuestionOptions(); TextView option1 = (TextView) findViewById(R.id.answer1); option1.setText(Utility.capitalise(answers.get(0))); TextView option2 = (TextView) findViewById(R.id.answer2); option2.setText(Utility.capitalise(answers.get(1))); TextView option3 = (TextView) findViewById(R.id.answer3); option3.setText(Utility.capitalise(answers.get(2))); TextView option4 = (TextView) findViewById(R.id.answer4); option4.setText(Utility.capitalise(answers.get(3))); } public void onClick(View arg0) { //validate a checkbox has been selected if (!checkAnswer()) return; //check if end of game if (currentGame.isGameOver()) { Intent i = new Intent(this, EndgameActivity.class); startActivity(i); finish(); } else { Intent i = new Intent(this, QuestionActivity.class); startActivity(i); finish(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: return true; } return super.onKeyDown(keyCode, event); } /** * Check if a checkbox has been selected, and if it has then check if its * correct and update gamescore */ private boolean checkAnswer() { String answer = getSelectedAnswer(); if (answer == null) { // Log.d("Questions", "No Checkbox selection made - returning"); return false; } else { // Log.d("Questions", // "Valid Checkbox selection made - check if correct"); if (currentQ.getAnswer().equalsIgnoreCase(answer)) { // Log.d("Questions", "Correct Answer!"); currentGame.incrementRightAnswers(); } else { // Log.d("Questions", "Incorrect Answer!"); currentGame.incrementWrongAnswers(); } return true; } } private String getSelectedAnswer() { RadioButton c1 = (RadioButton) findViewById(R.id.answer1); RadioButton c2 = (RadioButton) findViewById(R.id.answer2); RadioButton c3 = (RadioButton) findViewById(R.id.answer3); RadioButton c4 = (RadioButton) findViewById(R.id.answer4); if (c1.isChecked()) { return c1.getText().toString(); } if (c2.isChecked()) { return c2.getText().toString(); } if (c3.isChecked()) { return c3.getText().toString(); } if (c4.isChecked()) { return c4.getText().toString(); } return null; } 

我认为当你尝试进行对话时某个时刻活动不再存在(可能是在CountDownTimer接近结束时?!?)。

无论如何,我认为为每个问题完成并开始相同的活动并不是一个好主意,而是可以使用当前活动并简单地重新启动计时器。 例如:

 public class QuestionActivity extends SherlockActivity implements OnClickListener { private CountDownTimer mCountDown; @Override public void onCreate(Bundle savedInstanceState) { // ... mCountDown = new CountDownTimer(20000, 1000) { @Override public void onFinish() { // myCounter.setText("Time up!"); timeUp(context); } @Override public void onTick(long millisUntilFinished) { myCounter.setText("Time left: " + String.valueOf(millisUntilFinished / 1000)); } }.start(); // ... 

并在onClick回调中执行相同操作以设置新问题,停止旧计时器并重新启动新计时器:

 //check if end of game if (currentGame.isGameOver()) { Intent i = new Intent(this, EndgameActivity.class); startActivity(i); finish(); } else { if (mCountDown != null) { mCountDown.cancel(); } currentQ = currentGame.getNextQuestion(); setQuestions(); mCountDown = new CountDownTimer(20000, 1000) { @Override public void onFinish() { // myCounter.setText("Time up!"); timeUp(context); } @Override public void onTick(long millisUntilFinished) { myCounter.setText("Time left: " + String.valueOf(millisUntilFinished / 1000)); } }.start(); } 

此外,在DialogButton的回调中,我将在完成Activity之前关闭Dialog

 ((AlertDialog) dialog).dismiss(); QuestionActivity.this.finish();