Updating the Controller Layer

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

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

Open MainActivity.kt. Create a list of Question objects and an index for the list.

Listing 2.5  Adding a Question list (MainActivity.kt)

class MainActivity : AppCompatActivity() {

    private lateinit var trueButton: Button
    private lateinit var falseButton: Button

    private val questionBank = listOf(
            Question(R.string.question_australia, true),
            Question(R.string.question_oceans, true),
            Question(R.string.question_mideast, false),
            Question(R.string.question_africa, false),
            Question(R.string.question_americas, true),
            Question(R.string.question_asia, true))

    private var currentIndex = 0
    ...
}

Here you call the Question constructor several times and create a list of Question objects.

(In a more complex project, this list 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 list within your controller.)

You are going to use questionBank, currentIndex, and the properties in Question to get a parade of questions onscreen.

First add properties for the TextView and the new Button. Then get a reference for the TextView and set its text to the question at the current index. While you are at it, get a reference for the new Button as well (you will configure the click listener for the NEXT button later).

Listing 2.6  Wiring up the TextView (MainActivity.kt)

class MainActivity : AppCompatActivity() {

    private lateinit var trueButton: Button
    private lateinit var falseButton: Button
    private lateinit var nextButton: Button
    private lateinit var questionTextView: TextView
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        trueButton = findViewById(R.id.true_button)
        falseButton = findViewById(R.id.false_button)
        nextButton = findViewById(R.id.next_button)
        questionTextView = findViewById(R.id.question_text_view)

        trueButton.setOnClickListener { view: View ->
            ...
        }

        falseButton.setOnClickListener { view: View ->
            ...
        }

        val questionTextResId = questionBank[currentIndex].textResId
        questionTextView.setText(questionTextResId)
    }
}

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 make the NEXT button functional. Set a View.OnClickListener on it. This listener will increment the index and update the TextView’s text.

Listing 2.7  Wiring up the new button (MainActivity.kt)

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    falseButton.setOnClickListener { view: View ->
        ...
    }

    nextButton.setOnClickListener {
        currentIndex = (currentIndex + 1) % questionBank.size
        val questionTextResId = questionBank[currentIndex].textResId
        questionTextView.setText(questionTextResId)

    }

    val questionTextResId = questionBank[currentIndex].textResId
    questionTextView.setText(questionTextResId)
}

You now have the same code in two separate places that updates the text displayed in questionTextView. Take a moment to put this code into a function instead, as shown in Listing 2.8. Then invoke that function in the nextButton’s listener and at the end of onCreate(Bundle?) to initially set the text in the activity’s view.

Listing 2.8  Encapsulating with a function (MainActivity.kt)

class MainActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        nextButton.setOnClickListener {
            currentIndex = (currentIndex + 1) % questionBank.size
            val questionTextResId = questionBank[currentIndex].textResId
            questionTextView.setText(questionTextResId)
            updateQuestion()
        }

        val questionTextResId = questionBank[currentIndex].textResId
        questionTextView.setText(questionTextResId)
        updateQuestion()
    }

    private fun updateQuestion() {
        val questionTextResId = questionBank[currentIndex].textResId
        questionTextView.setText(questionTextResId)
    }
}

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. You will add a private named function to MainActivity to encapsulate code rather than writing similar code in two places:

    private fun checkAnswer(userAnswer: Boolean)

This function 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 MainActivity.kt, add the implementation of checkAnswer(Boolean) shown in Listing 2.9.

Listing 2.9  Adding checkAnswer(Boolean) (MainActivity.kt)

class MainActivity : AppCompatActivity() {
    ...
    private fun updateQuestion() {
        ...
    }

    private fun checkAnswer(userAnswer: Boolean) {
        val correctAnswer = questionBank[currentIndex].answer

        val messageResId = if (userAnswer == correctAnswer) {
            R.string.correct_toast
        } else {
            R.string.incorrect_toast
        }

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

Within the buttons’ listeners, call checkAnswer(Boolean), as shown in Listing 2.10.

Listing 2.10  Calling checkAnswer(Boolean) (MainActivity.kt)

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    trueButton.setOnClickListener { view: View ->
        Toast.makeText(
            this,
            R.string.correct_toast,
            Toast.LENGTH_SHORT
        )
            .show()
        checkAnswer(true)
    }

    falseButton.setOnClickListener { view: View ->
        Toast.makeText(
            this,
            R.string.correct_toast,
            Toast.LENGTH_SHORT
        )
            .show()
        checkAnswer(false)
    }
    ...
}

Run GeoQuiz. Verify that the toasts display the right message based on the answer to the current question and the button you press.

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

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