Android Gioco a Quiz – conto alla Rovescia per ogni qstion

Ho creato un Quiz app per Android utilizzando il tutorial qui: http://automateddeveloper.blogspot.co.uk/2011/06/getting-started-complete-android-app.html

Per ogni domanda, l’utente dovrà solo 20 secondi per rispondere. Se lui/lei non riesce a rispondere in 20 secondi, un AlertDialog popup e il gioco terminerà.

Per fare questo, ho aggiunto un contatore nel OnCreate metodo di 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();
}

Il contatore opere delle funzioni e visualizzazioni su schermo in modo corretto. Dopo aver risposto a una domanda, l’attività si sposta alla prossima domanda e il contatore si resetta da sola per 20 secondi.

Il problema

Questionario di 15 domande, dopo aver risposto a 3 o 4 domande, l’app si blocca e ottengo il seguente errore:

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

Credo che questo si riferisce alla AlertDialog. Ho guardato questo codice di errore su Stackoverflow e la soluzione più comune è quello di superare ActivityName.this come il contesto quando si costruisce il AlertDialog.

Purtroppo questo non risolve il problema.

Credo che il contatore è l’impostazione di un limite di tempo di 20 secondi per l’intera attività. La mia richiesta è di 20 secondi per ogni domanda.

Tuttavia, il contatore si azzera per 20 secondi quando l’utente preme il’ Next pulsante e l’attività si sposta alla prossima domanda.

Devo reimpostare il contatore quando l’utente preme il Next pulsante? Qui è il OnClickListener codice per il Next pulsante

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

Qualcuno mi può aiutare per il codice di una soluzione al mio problema?

Qui è tutto il codice in 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;
}

OriginaleL’autore tiptopjat | 2012-07-18

One Reply
  1. 7

    Penso che l’attività non esiste più, a un certo punto, quando si tenta di visualizzare la finestra di dialogo(probabilmente quando l’ CountDownTimer è vicino alla fine?!?).

    Comunque penso di rifinitura e partenza per la stessa attività per ogni domanda non è una buona idea, invece, si potrebbe utilizzare l’attività corrente e riavviare il timer. Per esempio:

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

    e nel onClick richiamata fare lo stesso con l’installazione di una nuova domanda, interrompere il timer vecchio e riavviare il timer di nuovo:

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

    Anche, nella richiamata per il Dialog‘s Button vorrei chiudere prima Dialog prima di finire il Activity:

    ((AlertDialog) dialog).dismiss();
    QuestionActivity.this.finish();
    Grazie tizio. Vorrei dare a questo una prova, quando torno a casa stasera.
    Ho aggiunto il codice e il contatore problema è stato risolto. Tuttavia, quando il quiz è finito, e ho EndgameActivity.class dopo 20 secondi mi arriva un WindowManager$BadTokenException errore. Sembra che il timer è ancora in esecuzione e cercando di visualizzare il AlertDialog. Io sto usando il finish() dopo l’avvio del EndgameActivity attività. Qualsiasi idea di cosa sto facendo di sbagliato?
    Aggiungere il codice per interrompere il timer per caso quando il gioco è finito: if (currentGame.isGameOver()) { if (mCountDown != null) { mCountDown.cancel(); } ... e vedere se si risolve il problema.
    Problema risolto! Grazie. Ho solo un problema ora. Nella mia soluzione originale, i pulsanti di opzione per ogni domanda sarebbe stata deselezionata quando si passa ad una nuova domanda. Dopo l’implementazione della soluzione, il pulsante di opzione selezionato dalla domanda precedente è ancora selezionato nella prossima domanda…
    Risolto con l’aggiunta di radioGroup.clearCheck() all’inizio di setQuestions() metodo.

    OriginaleL’autore Luksprog

Lascia un commento