Android Kotlin – Building a Times Tables App – Part 2

In a previous post, we built the first part of a times tables flash card app in Android Studio. So far, we have the main page of the app where a user can either select a specific table by entering a number, or leave it blank to practice all tables. In addition, we set up a radio group with two buttons, one for “Normal Mode” and the other for “Random Mode”.

Today, we’ll be implementing the page of the app that actually shows the user their table’s questions and answers. Let’s get right into it by creating a new activity.

When I wrote this, I was using Android Studio Arctic Fox | 2020.3.1 Patch 2.

The full code for this project is on my Github account:

https://github.com/jamesmcclay/android_kotlin_times_tables

Create a new activity

To create one, just go to File –> New –> Activity –> Empty Activity. I’m going to call my activity “TableActivity”:

New Android Activity Screen in Android Studio Arctic Fox

Now that we have a fresh activity, we can create the layout elements.

Creating layout elements

We can go ahead and just delete any auto-populated content in the layout. The first thing we’ll want to create is a toolbar, so that we can put a back button on it. My initial RelativeLayout looks like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:minHeight="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:titleTextColor="@android:color/white"
        android:background="?attr/colorPrimary">
    </androidx.appcompat.widget.Toolbar>

</RelativeLayout>

This is some boilerplate that creates a toolbar with an ID of toolbard so we can grab it from our Kotlin code later.

As for the view itself – my idea for the layout of this page was to have just three elements. A TextView to hold the question, a TextView to hold the answer, and a Button to allow the user to show the answer when they’re ready. Between the RelativeLayout tags, I’ll write the XML for the elements:

<TextView
    android:id="@+id/textview_question"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:text=""
    android:textAlignment="center"
    android:textSize="32sp" />

<TextView
    android:id="@+id/textview_answer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/textview_question"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="50dp"
    android:text=""
    android:textAlignment="center"
    android:textSize="32sp" />

<Button
    android:id="@+id/button_show"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/textview_answer"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="60dp"
    android:text="Show answer"
    android:width="150dp"/>

Nothing special here, just some text and a button on the screen. That’s all we need for a basic flashcard app.

TableActivity.kt

The main logic of the app is going in this file. Not that it’s anything complicated, but there’s a few calculations that need to be made.

Before we do any of that, some global variables need to be defined so we can store some (state) information there. At the top of the file right after the class declaration, we’ll put these in:

class TableActivity : AppCompatActivity() {

    var mode:String = "" //Normal or Random mode
    var tableMode = "normal" //A single table or all tables
    var table:Int = 0 //The number of the current table
    var multiplier = 1 //The number to multiply by the table
    var answerShowing = false //The state of whether answer is showing

    lateinit var appBarConfiguration: AppBarConfiguration //The Toolbar

The lateinit keyword just means that instead of giving the variable a value now, we promise to give it a value before we use it, or the app will crash. In this case, we’re going to do the toolbar code in onCreate, so I think we’re ok.

In addition, as was instructed to me by the Android documentation, we need to add this (overridden) function to our class to make the back button work:

override fun onSupportNavigateUp(): Boolean {
    onBackPressed()
    return true
}

onCreate function

Now let’s put some stuff in onCreate. First is the binding to the layout so we can access all the elements, it’s pretty quick:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding = ActivityTableBinding.inflate(layoutInflater)
    setContentView(binding.root)

Next is the toolbar code – I honestly struggled quite a bit with this part and ended up finding the solution on StackOverflow and can’t remember what page, sorry 🙁 But this magic incantation seemed to work:

val toolbar = binding.toolbar
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Practice!"

Then we put the layout elements (text fields and button) in some variables:

val question = binding.textviewQuestion
val answer = binding.textviewAnswer
val button = binding.buttonShow

Now let’s set the mode and table global variables to values sent from the previous activity. You’ll remember if the user didn’t put any value into the EditText for the table, we set the value to 0 so it would be a number. Let’s get the values now:

mode = intent.getStringExtra("mode").toString()
table = intent.getStringExtra("table").toString().toInt()

if (table == 0) {
    tableMode = "all"
    table = 2
}

The above is a bit confusing so let me explain – if the user selected a specific table, it will be a number and we can just work with that. But if it’s 0, they want to do all tables. We still need to use the table integer and increment it up as the user works through the tables. We need a way to know that we are in “all tables mode”, which is why I created the global variable tableMode. So if table is 0, we’ll set tableMode to all, and table we’ll set to 2. Why set to 2? Nobody wants to do tables 0 and 1, they’re too easy. We’ll start at 2.

We also need to run nextQuestion once on startup so the first question will show. All subsequent question will show when the user taps the button:

nextQuestion(question, answer, button)

The last chore in onCreate is to create an onClickListener for the showButton. This button is actually responsible for two things – if the answer isn’t showing and it’s clicked, it needs to show the answer. If the answer is showing, it should go to the next question. Hence the need for an answerShowing global variable. Here’s the listener:

button.setOnClickListener {
    if (answerShowing == false) {
        showAnswer(question, answer, button)
    }else {
        nextQuestion(question, answer, button)
    }
}

We’ll send the question, answer, and button layout items through as arguments so they can be updated by either the showAnswer or nextQuestion functions, whichever runs.

Done with onCreate. Let’s implement nextQuestion and showAnswer.

nextQuestion function

This function got a little more complicated than I would have liked, but it works. I’ll try to break it down so it’s clear what’s happening:

fun nextQuestion(question:TextView, answer:TextView, button: Button) {
    if (mode == "random") {
        multiplier = (2..12).random()
        if (tableMode == "all") {
            table = (2..9).random()
        }
    }else{
        multiplier += 1
        if (multiplier == 13) {
            multiplier = 2
            if (tableMode == "all") {
                table += 1
            }
        }
    }
    question.text = "$table X $multiplier = "
    answerShowing = false
    answer.text = ""
    button.text = "Show Answer"
}

This function starts with a check to see if random mode is on or not. If it’s random, we set the multiplier to something random between 2 and 12 (I assume people want to learn their tables up to 12). Then we check to see if we’re doing a specific table, or all of them. If it’s a specific table, we can use the existing fixed value of table. If we’re doing all tables, we’ll get a random table since this is random mode.

If the check for random is false, we’re incrementing the multiplier sequentially, so we increase it by 1. If multiplier is now 13, set it back to 2 (most people don’t learn tables past 12). In addition, when the multiplier is 13, increment the table by 1 so the user can move on to the next one.

That should do it for the logic. The lines after that are setting the text of the question, setting answerShowing to false (since it’s showing a new question now), then removing the answer text, and finally changing the button text to “Show Answer”.

showAnswer function

This function is much simpler – as the name suggests, it’s just showing the answer.

fun showAnswer(question:TextView, answer:TextView, button: Button) {
    val theAnswer = table * multiplier
    answer.text = "$theAnswer"
    answerShowing = true
    button.text = "Next"
}

Done with code!

Try it out

Everything is looking good!

Hope you liked this one. Let me know if you have any questions.

Leave a Reply

Your email address will not be published. Required fields are marked *