Updating the Controller Layer

In the previous chapter, there was not much happening in GeoQuiz’s one controller, QuizActivity. It displayed the layout defined in activity_quiz.xml. It set listeners on two buttons and wired them to make toasts.

Now that you have multiple questions to retrieve and display, QuizActivity will have to work harder to tie GeoQuiz’s model and view layers together.

Open QuizActivity.java. Add variables for the TextView and the new Button. Also, create an array of Question objects and an index for the array.

Listing 2.6  Adding variables and a Question array (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {

    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;
    ...

Here you call the Question constructor several times and create an array of Question objects.

(In a more complex project, this array would be created and stored elsewhere. In later apps, you will see better options for storing model data. For now, we are keeping it simple and just creating the array within your controller.)

You are going to use mQuestionBank, mCurrentIndex, and the accessor methods in Question to get a parade of questions on screen.

First, get a reference for the TextView and set its text to the question at the current index.

Listing 2.7  Wiring up the TextView (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_quiz);

        mQuestionTextView = (TextView) findViewById(R.id.question_text_view);
        int question = mQuestionBank[mCurrentIndex].getTextResId();
        mQuestionTextView.setText(question);

        mTrueButton = (Button) findViewById(R.id.true_button);
        ...
    }
}

Save your files and check for any errors. Then run GeoQuiz. You should see the first question in the array appear in the TextView.

Now let’s see about the NEXT button. First, get a reference to the button. Then set a View.OnClickListener on it. This listener will increment the index and update the TextView’s text.

Listing 2.8  Wiring up the new button (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mFalseButton.setOnClickListener(new View.OnClickListener() {
            ...
            }
        });

        mNextButton = (Button) findViewById(R.id.next_button);
        mNextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCurrentIndex = (mCurrentIndex + 1) % mQuestionBank.length;
                int question = mQuestionBank[mCurrentIndex].getTextResId();
                mQuestionTextView.setText(question);
            }
        });
    }
}

You now have code in two separate places that updates the mQuestionTextView variable. Take a moment to put this code into a private method instead, as shown in Listing 2.9. Then call that method in the mNextButton’s listener and at the end of onCreate(Bundle) to initially set the text in the activity’s view.

Listing 2.9  Encapsulating with updateQuestion() (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mQuestionTextView = (TextView) findViewById(R.id.question_text_view);
        int question = mQuestionBank[mCurrentIndex].getTextResId();
        mQuestionTextView.setText(question);
        ...
        mNextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCurrentIndex = (mCurrentIndex + 1) % mQuestionBank.length;
                int question = mQuestionBank[mCurrentIndex].getTextResId();
                mQuestionTextView.setText(question);
                updateQuestion();
            }
        });

        updateQuestion();
    }

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

Run GeoQuiz and test your new NEXT button.

Now that you have the questions behaving appropriately, it is time to turn to the answers. At the moment, GeoQuiz thinks that the answer to every question is true. Let’s rectify that. Here again, you will implement a private method to encapsulate code rather than writing similar code in two places.

The method that you are going to add to QuizActivity is:

    private void checkAnswer(boolean userPressedTrue)

This method will accept a boolean variable that identifies whether the user pressed TRUE or FALSE. Then, it will check the user’s answer against the answer in the current Question object. Finally, after determining whether the user answered correctly, it will make a Toast that displays the appropriate message to the user.

In QuizActivity.java, add the implementation of checkAnswer(boolean) shown in Listing 2.10.

Listing 2.10  Adding checkAnswer(boolean) (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
    }

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

Within the button’s listeners, call checkAnswer(boolean), as shown in Listing 2.11.

Listing 2.11  Calling checkAnswer(boolean) (QuizActivity.java)

public class QuizActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mTrueButton = (Button) findViewById(R.id.true_button);
        mTrueButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(QuizActivity.this,
                               R.string.correct_toast,
                               Toast.LENGTH_SHORT).show();
                checkAnswer(true);
            }
        });

        mFalseButton = (Button) findViewById(R.id.false_button);
        mFalseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(QuizActivity.this,
                               R.string.incorrect_toast,
                               Toast.LENGTH_SHORT).show();
                checkAnswer(false);
            }
        });
        ...
    }
    ...
}

GeoQuiz is ready to run again. Let’s get it running on a real device.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.118.198