java Android 问答游戏 - 每个问题的倒数计时器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11532684/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:28:14  来源:igfitidea点击:

Android Quiz Game - Countdown timer for each qstion

javaandroidtimercountdown

提问by tiptopjat

I have created a Quiz app for Android using the tutorial here: http://automateddeveloper.blogspot.co.uk/2011/06/getting-started-complete-android-app.html

我使用这里的教程为 Android 创建了一个测验应用程序:http: //automateddeveloper.blogspot.co.uk/2011/06/getting-started-complete-android-app.html

For each question, the user will only have 20 seconds to answer it. If he/she fails to answer in 20 seconds, an AlertDialogwill popup and the game will terminate.

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

To do this, I have added a counter in the OnCreatemethod of QuestionActivity class:

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

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();
}

The counter works displays and functions on screen correctly. After answering a question, the activity moves to the next question and the counter resets itself to 20 seconds again.

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

The problem

问题

The quiz has 15 questions, after answering 3 or 4 questions, the app crashes and I get the following error:

测验有 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?

I believe this relates to the AlertDialog. I have looked up this error code on Stackoverflow and the popular solution is to pass ActivityName.thisas the context when building the AlertDialog.

我相信这与AlertDialog. 我在 Stackoverflow 上查找过这个错误代码,流行的解决方案是ActivityName.this在构建AlertDialog.

Unfortunately this does not solve the problem.

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

I believe the counter is setting a time limit of 20 seconds for the whole activity. My requirement is 20 seconds for each question.

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

However, the counter resets to 20 seconds when the user press the' Nextbutton and the activity moves to the next question.

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

Should I be resetting the counter when the user presses the Nextbutton? Here is the OnClickListenercode for the Nextbutton

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

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();

Can anyone help me code a solution to my problem?

谁能帮我编写代码来解决我的问题?

Here is all the code in QuestionActivity.class

这里是所有的代码 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<String> 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;
}

回答by Luksprog

I think the activity doesn't exist anymore at a certain point when you try to make the dialog(probably when the CountDownTimeris near the end?!?).

我认为当您尝试进行对话时(可能CountDownTimer是在接近尾声时?!?),该活动在某个时刻不再存在。

Anyway I think finishing and starting the same activity for each question isn't such a good idea, instead you could use the current activity and simply restart the timer. For example:

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

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();
      // ... 

and in the onClickcallback do the same to setup a new question, stop the old timer and restart the new timer:

并在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();  
}

Also, in the callback for the Dialog's ButtonI would first close the Dialogbefore finishing the Activity:

另外,在Dialog's的回调中,Button我会Dialog在完成之前先关闭Activity

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