Android测验游戏 – 每个qstion的倒数计时器
我使用以下教程为Android创建了一个Quiz应用程序: http : //automateddeveloper.blogspot.co.uk/2011/06/getting-started-complete-android-app.html
对于每个问题,用户只有20秒的时间来回答它。 如果他/她在20秒内未能回答,则会弹出AlertDialog
,游戏将终止。
为此,我在QuestionActivity class
的OnCreate
方法中添加了一个计数器:
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(); }
此外,在Dialog
的Button
的回调中,我将在完成Activity
之前关闭Dialog
:
((AlertDialog) dialog).dismiss(); QuestionActivity.this.finish();