Solution to Challenge 3.7

Dear all,
The following solution is imperfect since the “TRUE” or “FALSE” button has to be pressed twice to be disabled. I don’t have any idea to fix it at present and I am looking forward to your suggestions.

package com.bignerdranch.android.geoquiz;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class QuizActivity extends AppCompatActivity {

    private static final String TAG="QuizActivity";
    private static final String KEY_INDEX="index";
    private Button mTrueButton;
    private Button mFalseButton;
    private Button mNextButton;
    private TextView mQuestionTextView;

    private Question[] mQuestionBank=new Question[]{
            new Question(R.string.question_australia,true),
            new Question(R.string.question_oceans,true),
            new Question(R.string.question_mideast,false),
            new Question(R.string.question_africa,false),
            new Question(R.string.question_americas,true),
            new Question(R.string.question_asia,true)
    };

    private int mCurrentIndex=0;
    private int[] mAnswered={0,0,0,0,0,0};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG,"onCreate(Bundle) called");
        setContentView(R.layout.activity_quiz);

        if(savedInstanceState!=null){
            mCurrentIndex=savedInstanceState.getInt(KEY_INDEX,0);
        }

        mQuestionTextView=(TextView)findViewById(R.id.question_text_view);


        mTrueButton=(Button) findViewById(R.id.true_button);
        mTrueButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                if(mAnswered[mCurrentIndex]==1){
                    mFalseButton.setEnabled(false);
                    mTrueButton.setEnabled(false);
                } else {
                    checkAnswer(true);
                    mAnswered[mCurrentIndex]=1;
                }

            }
        });

        mFalseButton=(Button) findViewById(R.id.false_button);
        mFalseButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                if (mAnswered[mCurrentIndex] == 1) {
                    mFalseButton.setEnabled(false);
                    mTrueButton.setEnabled(false);
                } else {
                    checkAnswer(false);
                    mAnswered[mCurrentIndex] = 1;
                }
            }
        });

        mNextButton=(Button) findViewById(R.id.next_button);
        mNextButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                mCurrentIndex = (mCurrentIndex + 1)%mQuestionBank.length;
                if (mAnswered[mCurrentIndex] == 0) {
                    mTrueButton.setEnabled(true);
                    mFalseButton.setEnabled(true);
                    updateQuestion();
                }else {
                    updateQuestion();
                }
            }
        });

        updateQuestion();
    }

    @Override
    public void onStart(){
        super.onStart();
        Log.d(TAG,"onStart() called");
    }

    @Override
    public void onResume(){
        super.onResume();
        Log.d(TAG,"onResume() called");
    }

    @Override
    public void onPause(){
        super.onPause();
        Log.d(TAG,"onPause() called");
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState){
        super.onSaveInstanceState(savedInstanceState);
        Log.i(TAG,"onSaveInstanceState");
        savedInstanceState.putInt(KEY_INDEX,mCurrentIndex);
    }

    @Override
    public void onStop(){
        super.onStop();
        Log.d(TAG,"onStop() called");
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        Log.d(TAG,"onDestroy() called");
    }

    private void updateQuestion(){
        int question=mQuestionBank[mCurrentIndex].getTextResId();
        mQuestionTextView.setText(question);
    }

    private void checkAnswer(boolean userPressedTrue){
        boolean answerIsTrue=mQuestionBank[mCurrentIndex].isAnswerTrue();

        int messageResId=0;

        if(userPressedTrue==answerIsTrue){
            messageResId=R.string.correct_toast;
        }else{
            messageResId=R.string.incorrect_toast;
        }

        Toast.makeText(this,messageResId,Toast.LENGTH_LONG)
                .show();
    }
}

The reason why you have to press twice is because the first time the if block won’t get executed. The second time you click, it will actually execute the if block since only then the mAnswered[mCurrentIndex]==1.
To be honest, there’s isn’t a point for implementing an if-else block there. Everytime you answer a question, you want to disable the buttons, right? So when you answer, you disable both buttons directly after it, without checking for a condition.

Hopefully that clears up some confusion :slight_smile: If you still got question, please don’t hesitate to ask.

Hello Boontje,
Thank you very much for your reply. I changed my solution according to your suggestion and now the it works! That’s amazing! I love the joy of success in programming!
Based on your tips, I added another marking function required by Challenge 3.8 . Here is the code:

package com.bignerdranch.android.geoquiz;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class QuizActivity extends AppCompatActivity {

private static final String TAG="QuizActivity";
private static final String KEY_INDEX="index";
private int scores=0;
private int count=0;
private Button mTrueButton;
private Button mFalseButton;
private Button mNextButton;
private TextView mQuestionTextView;

private Question[] mQuestionBank=new Question[]{
        new Question(R.string.question_australia,true),
        new Question(R.string.question_oceans,true),
        new Question(R.string.question_mideast,false),
        new Question(R.string.question_africa,false),
        new Question(R.string.question_americas,true),
        new Question(R.string.question_asia,true)
};

private int mCurrentIndex=0;
private int[] mAnswered={0,0,0,0,0,0};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG,"onCreate(Bundle) called");
    setContentView(R.layout.activity_quiz);

    if(savedInstanceState!=null){
        mCurrentIndex=savedInstanceState.getInt(KEY_INDEX,0);
    }

    mQuestionTextView=(TextView)findViewById(R.id.question_text_view);


    mTrueButton=(Button) findViewById(R.id.true_button);
    mTrueButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
                mAnswered[mCurrentIndex]=1;
                mFalseButton.setEnabled(false);
                mTrueButton.setEnabled(false);
                checkAnswer(true);
        }
    });

    mFalseButton=(Button) findViewById(R.id.false_button);
    mFalseButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            mAnswered[mCurrentIndex] =1;
                mFalseButton.setEnabled(false);
                mTrueButton.setEnabled(false);
                checkAnswer(false);

            }
    });

    mNextButton=(Button) findViewById(R.id.next_button);
    mNextButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            mCurrentIndex = (mCurrentIndex + 1)%mQuestionBank.length;
            if (mAnswered[mCurrentIndex] == 0) {
                mTrueButton.setEnabled(true);
                mFalseButton.setEnabled(true);
                updateQuestion();
            }else {
                for(int j=0;j<mQuestionBank.length;j++){
                count+=mAnswered[j];
            };
                if(count==mQuestionBank.length){
                    Toast.makeText(getApplicationContext(),"score is "+String.valueOf(Math.round(scores/(float)mQuestionBank.length*100)),Toast.LENGTH_SHORT).show();
                }else {
                    count=0;
                }
                updateQuestion();
            }
        }
    });

    updateQuestion();
}

@Override
public void onStart(){
    super.onStart();
    Log.d(TAG,"onStart() called");
}

@Override
public void onResume(){
    super.onResume();
    Log.d(TAG,"onResume() called");
}

@Override
public void onPause(){
    super.onPause();
    Log.d(TAG,"onPause() called");
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState){
    super.onSaveInstanceState(savedInstanceState);
    Log.i(TAG,"onSaveInstanceState");
    savedInstanceState.putInt(KEY_INDEX,mCurrentIndex);
}

@Override
public void onStop(){
    super.onStop();
    Log.d(TAG,"onStop() called");
}

@Override
public void onDestroy(){
    super.onDestroy();
    Log.d(TAG,"onDestroy() called");
}

private void updateQuestion(){
    int question=mQuestionBank[mCurrentIndex].getTextResId();
    mQuestionTextView.setText(question);
}

private void checkAnswer(boolean userPressedTrue){
    boolean answerIsTrue=mQuestionBank[mCurrentIndex].isAnswerTrue();

    int messageResId=0;

    if(userPressedTrue==answerIsTrue){
        messageResId=R.string.correct_toast;
        scores++;
    }else{
        messageResId=R.string.incorrect_toast;
    }

    Toast.makeText(this,messageResId,Toast.LENGTH_SHORT)
            .show();
}

}

Great to hear! I love your reaction, I can feel your passion for programming haha!

I assume your solution works? In that case, good job! There are some minor things I can touch on, which is duplicate code and the complexity of the onClick function on the next-button. Setting the mTrue or mFalse button enabled is duplicated amongst three buttons, and at all the three buttons they do the same thing, except on a different button. You could place that functionality in it’s own function and call that function where you have to set the buttons enabled.
Like so:

private void buttonsEnabled(boolean enabled) {
mTrueButton.setEnabled(enabled);
mFalseButton.setEnabled(enabled);
}

That same principle counts towards the complexity of your next button, it does alot of things right now. Looping, checking for conditions. Placing those complexities in their own functions could increase the readability of the onClick function. Be wary tho, since it could also mean people have to search for the logic. Some of the logic in that onClick function could even be transferred over to functions you already defined :slight_smile:

As you can see, it’s mainly refactoring of code, cleaning up. Its not too important right now, since you just want it to work and it’s mainly for yourself. But it can be a good practice for nice programming habits :slight_smile:

Besides that, good job again on completing the challenge! Happy coding!

Hi Boontje,
There is still a small but last bug in the code. After all the questions have been answered,the score appears only once when I click the NEXT button twice. Anyway, the score is supposed to pop up whenever I press NEXT after all questions are done. I can not explain why this would happen,which is rather annoying. Could you please shed light on it?
Best wishes.

Hey Kafka,

Could you share the code which resides within the mNextButton? I figured you must have changed the implementation to fix the previous bug. Seeing the changes would help, to see the logic you implemented. It most likely got to do something with an if statement, but I can’t say for sure.

My apologies for the late reply.

in the mNextButton.setOnClickListener add “count=0;” after “if” statement, remove “else”

if(count==mQuestionBank.length){
Toast.makeText(getApplicationContext(),"score is "+String.valueOf(Math.round(scores/(float)mQuestionBank.length*100)),Toast.LENGTH_SHORT).show();
}
count=0;
updateQuestion();