Android IP Subnet Practice App – Part 1 – External Libraries

I started app development on iOS, Swift and Xcode, so naturally I was used to Cocoa Pods to get external libraries. Android Studio (with Kotlin) has a similar method, but of course it’s a bit different. I’m no Android expert but I’ll share my learnings so far trying to put together an app that allows the user to practice calculating IPv4 subnets. If you’re not familiar with those, they are a crucial skill to understanding TCP/IP networking.

Concept

Just to get a very basic app working, we’ll build an experimental layout in order to test and see if the subnetting code is working. The basic idea is to get something that looks like this:

Subnet Practice Concept App

The top element is a text field that captures the user’s input, while the bottom element is a button that runs the code to find the “network address”, or the first IP address in a subnet, given an IP address and subnet mask. Above, we can see that from “192.168.0.5/24”, the network address “192.168.0.0/24” has been calculated after “TEST” was pressed. That’s what we’re shooting for.

Layout

We’ll create these three simple elements on a Relative Layout in activity_main.xml like this:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/edittext_entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="100dp"
        android:text="192.168.0.5/24" />

    <TextView
        android:id="@+id/textview_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/edittext_entry"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="60dp" />

    <Button
        android:id="@+id/button_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/textview_result"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="60dp"
        android:text="Test" />

</RelativeLayout>

Hopefully this is pretty simple – it just creates the three elements and lays them out vertically in the center of the screen.

Adding an external library

Googling around, I found an IP address processing library on Github here:

https://github.com/seancfoley/IPAddress

On the Github page, it explicitly states the Maven Central (a large repository of libraries, connectivity to it is built-in to Android Studio) group and artifact ID’s, as well as the versions:

  • Maven group id: com.github.seancfoley
  • Maven artifact id: ipaddress
  • Maven versions: 2.0.2, 3.0.0, 4.3.3, 5.3.3

We can take this information and put a line in the app-level build.gradle file to download and install the library. Find the dependencies section (usually at the bottom) and add this line:

dependencies {
    //Others here removed for brevity
    implementation 'com.github.seancfoley:ipaddress:5.3.3'
}

Sync the gradle file and the library should be installed!

Kotlin code

In MainActivity.kt, we’ll connect to the layout elements and add logic. Make sure to enable view binding. Then we’ll write an onCreate function that looks like this:

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

        val binding = ActivityMainBinding.inflate(layoutInflater) #view binding
        setContentView(binding.root) #view binding

        val et = binding.edittextEntry #grab the EditText
        val r = binding.textviewResult #grab the TextView (result)
        val b = binding.buttonTest     #grab the Button

        b.setOnClickListener() {
            val str = et.text.toString() #get text from EditText
            val netAddr = IPAddressString(str).toAddress().toZeroHost().toString() #Magic to calculate network address
            r.text = netAddr #set TextView (result) to network address
        }
    }
}

This line:

val netAddr = IPAddressString(str).toAddress().toZeroHost().toString()

…takes whatever string is in the EditText and does these steps:

  • IPAddressString(str) turns the string into an IP address string, which is necessary for parsing the original string to a properly formatted IP address.
  • .toAddress() converts the string to an IP address object
  • .toZeroHost() finds the lowest IP address in the subnet, usually called the network address or subnet address. This library calls it a Zero Host.
  • .toString() converts the network address back to a string so it can be put in the TextView

This is definitely where the magic is happening in this code.

Hope this was all clear enough. Leave a comment or send me a message if it’s not!

How To Publish An Android App On The Google Play Store

In a previous post, we created a simple app for practicing times tables. Then we added Google AdMob to it to display a basic ad banner at the bottom of the app. Today, we’re going to get the app published and available on the Google Play Store.

Create a developer account

Becoming an official developer with Google costs a one-time $25. It all starts here:

https://play.google.com/console

If you already have a google account, just follow the prompts to make your account a developer account.

Developer account creation page

Once your account is a developer account, you’ll need to upload a document that proves your identity.

Identity verification page

Verification usually takes a day or two to complete.

Create an app

Now we’re ready to create our first app on the store.

Play Store Console App Creation

The app creation process takes some time, and if you’re really serious about it, some planning. I won’t show all the screenshots, that would get a little long. The times tables app is very simple so we can move through it pretty quick.

Step 1 – basic details

We’ll need to give it a name, default language, whether it’s a game, and whether it’s paid or free. Be careful on that last one, once it’s set you can’t change it later.

Step 3 – App setup

App setup process

Google wants to know a fair amount about the app before it’s published. Some of it is for their own internal policies or data collection, others are to comply with various laws in the countries the app can be available in.

  • App access – whether your whole app is available immediately or if there is a paywall.
  • Ads – whether your app contains ads or not.
  • Content rating – a questionnaire about the content of your app.
  • Target audience – the age your app might be targeted to.
  • News apps – whether or not your app contains news.
  • COVID-19 – whether or not your app is for tracing COVID-19.
  • Data safety – you must disclose what kind of data your app collects. You also need to provide a link to a privacy policy for your app, so you’ll need to create both the policy and the page if you haven’t already.
  • Select an app category and provide contact details – a few questions about what categories your app falls under.
  • Set up your store listing – see below

Step 4 – Set up store listing

The store listing setup area will collect a bunch of information that is used to build your app’s Play Store page.

Store listing setup page

We need to upload the app icon, along with a feature graphic. A feature graphic is important if the app ever becomes popular and Google wants to feature it on the app store:

Then it’s time for screenshots:

Once we have all that stuff input and uploaded, we should be good on the store listing section. We should now be able to complete the final section to release the app on the Play Store.

Release the app on the Play Store

Now that we’ve done all the work to get the app ready, the “Publish your app on Google Play” section at the very bottom on the app’s main dashboard should be available. You’ll need to skip all the sections about testing and pre-releasing. It looks like this:

First check all countries in “Select countries and regions”, unless you have a reason not to select them all. Then click on the “Create a new release” button. On this page we’re actually going to upload a copy of the app code.

In Android Studio, you can create a bundle from Build –> Generate Signed Bundle:

Creating a Signed Bundle in Android Studio

If this is your first time creating a signed bundle, you’ll need to create a key store. Just fill in the information, it’s part of the X.509 certificate standard so it asks you for a bunch of identifying information:

Make a note of the build file destination, and create the bundle. Then upload the “.aab” file in on this page. After entering some quick details on the release at the bottom, we’re good to go.

We are now finally ready to roll it out to the world! On the Review Release page, we can click “Start rollout to Production”, which means we have completed all preparation steps!

Final release review page

Clicking the rollout button will send the app to Google, where it will be reviewed by human beings to ensure the app is safe/secure/compliant and otherwise OK to release to the world. If all goes well, the app should be available on the store within 3 days, sometimes taking up to 7, according to Google.

Congratulations!

Monetize Your App – Google AdMob

In the last couple of posts, we wrote a simple times tables flash card app. Let’s add some advertisements to it so we can make some money if anybody decides to actually use it.

Enter Google AdMob, one of the simplest and easiest ways to monetize an app.

The base code that we’ll be adding to is here on my Gihub account:

https://github.com/jamesmcclay/android_kotlin_times_tables

Let’s apply and get some ads popping up in our app!

Start the process

The application process starts here:

https://admob.google.com/home/

Clicking on “Get Started” will do what it promises.

If you’re already logged in with a Google Account, this part is easy. Your account will be created and you’ll be taken to the main AdMob page:

Google AdMob Dashboard

Click on “Add Your First App” to start adding an app.

Add your app

This part is pretty quick too. Just follow the prompts, answer the questions and create your app.

Now that we’ve created an app, we’ll need to add an ad to it. Once we’re done creating the app it leads us to the main page for the app. Clicking on “Add Ad Unit” will take us through the process to create an ad.

Create an ad unit

Ad units are just an ad within the app. There’s several different types to choose from. Some are simpler and less intrusive like the banner, and others take up the whole page and completely interrupt the flow of the app. Choose wisely. In this case, we’ll pick the simplest one, the banner.

Once the ad unit is created, we’ll get some identifiers we can use in our code to display the ad and connect it to our account to get paid.

Add the SDK

Now it’s time to write some code. We’re mostly going to be using the code given to us by Google, but since it’s in code we have a lot of control over how/when/if the ad is displayed. We’re following the quick start instructions on the Google documentation found here:

https://developers.google.com/admob/android/quick-start

We need to add some stuff to the build.gradle file located in the root directory (not the app-level one):

buildscript {
    repositories {
        google()
        mavenCentral()
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

I also ran into an issue where I had to change a line in settings.gradle to be this:

repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)

The key was changing “FAIL_ON_PROJECT_REPOS” to “PREFER_SETTINGS”. After that, syncing gradle worked.

Now we need to add the dependency to the app-level build.gradle file (the other one) like this:

dependencies {
  implementation 'com.google.android.gms:play-services-ads:20.4.0'

  // For apps targeting Android 12, add WorkManager dependency.
  constraints {
    implementation('androidx.work:work-runtime:2.7.0') {
        because '''androidx.work:work-runtime:2.1.0 pulled from play-services-ads
                   has a bug using PendingIntent without FLAG_IMMUTABLE or
                   FLAG_MUTABLE and will fail in apps targeting S+.'''
    }
  }
}

Then we need to add the follow to AndroidManifest.xml. Make sure you put in the Application ID for your app that’s in the Google AdMob dashboard. It’s not the Ad ID that you created, the app ID. I got confused, so I thought I’d specifically call it out:

<manifest>
    <application>
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
    </application>
</manifest>

With that, the SDK is added to the project. Next step is to initialize it.

Initialize the SDK

To initialize, we need to add the import at the top of the TableActivity.kt file (we’re going to put this on the flash card screen) and run the initializer inside onCreate. We’ll also add a global variable called mAdView to connect to adView (which we’ll create next):

import com.google.android.gms.ads.MobileAds

class TableActivity : AppCompatActivity() {

    lateinit var mAdView : AdView

    override fun onCreate(savedInstanceState: Bundle?) {

        MobileAds.initialize(this) {}

        mAdView = binding.adView
        val adRequest = AdRequest.Builder().build()
        mAdView.loadAd(adRequest)

Now all we need to do is add an AdView to the layout file so there’s an actual spot for ads. In the activity_table.xml file, we’ll stick this at the bottom, it came right from the Google documentation:

<com.google.android.gms.ads.AdView
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:id="@+id/adView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_alignParentBottom="true"
    ads:adSize="BANNER"
    ads:adUnitId="ca-app-pub-3940256099942544/6300978111">
</com.google.android.gms.ads.AdView>

You’ll notice there’s a real adUnitId in there, that’s on purpose. That’s actually the Google AdMob official test ID, we’re supposed to use that for testing. You can get your account suspended if you use your actual AdMob production ad ID.

And that should do it! When we fire up the app, we should see a test banner at the bottom of the flash card screen

Happy coding!

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.

Android Kotlin – Building a Times Tables App – Part 1

Google’s Android Studio is a pretty awesome tool for building Android apps, but after building a times tables app in python and HTML, I’ll say doing an Android version was a bit more complicated. But with a little bit of knowledge about how the basics of Android Studio works along with some knowledge of Kotlin, you can have a basic app up and running in very little time. Today I’m building an app that is basically flash cards for times tables, with a couple different modes. I’ve split this up into two posts since there’s a fair amount of code.

Part 2 of this post is here.

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 project

We start by creating a new project, with an empty activity.

New project screen in Android Studio

Give your project a name, and make sure to set the language as Kotlin. Click finish, and you have a brand new project!

Write the layout code

Android Studio takes you to the MainActivity.kt file off the bat, but we’re going to jump into the layout file and create the interface elements. At the top of the screen, you should see a tab that says activity_main.xml, that’s where we can create the first page elements of app.

Opening up activity_main.xml, you’ll need to click on “split” near the top right so you can see the code as well as a rending of it on a mock phone. There’s a bunch of code already in there but you can delete all that.

First I’m going to create a RelativeLayout:

<?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">

</RelativeLayout>

If you just type “Re”, RelativeLayout will probably autopopulate and you can press enter to get it and a bunch of pre-written code for you. No need to type all that stuff.

Text items

Inside the RelativeLayout (between the opening and closing <RelativeLayout> tags), I’ll create some text. These will just be banners introducing the app and instructing the user to enter a table to practice. This can be done with the element TextView:

    <TextView
        android:id="@+id/textview_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="100dp"
        android:text="James McClay's\nTimes Tables!"
        android:textAlignment="center"
        android:textSize="32sp" />

    <TextView
        android:id="@+id/textview_select"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textview_title"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="30dp"
        android:text="Practice all tables\n Or enter a table to practice:"
        android:textAlignment="center"
        android:textSize="24sp" />

I thought about commenting all these to explain what they’re doing, but it seems like they’re all pretty self-explanatory. It’s basically just putting some static text on the layout of the app, centering it, setting the font size, etc.

Next we’ll create a text entry field where the user can either leave it blank to practice all times tables or enter a specific one. This is done with the element EditText:

    <EditText
        android:id="@+id/edittext_timestable"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textview_select"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="30dp"
        android:hint="All tables"
        android:inputType="number"
        android:textAlignment="center"
        android:textSize="24sp" />

All elements have been given an "@+id", and using layout_below we can tell elements to go below another one.

Button and radio group

Next we’ll need a start button to send the user to the view that shows times tables questions. A button can be created with Button:

    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/edittext_timestable"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:text="Start!" />

Finally, we’ll create a RadioGroup to hold two radio button buttons. I thought having a normal, sequential mode as well as a random mode would be beneficial. The RadioGroup means that only one RadioButton can be selected in the group. Also, RadioButtons have a special property called onClick, where you can specify what function to run when one of the buttons is clicked and selected.

    <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button_start"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        >

    <RadioButton
        android:id="@+id/radio_normal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onRadioButtonClicked"
        android:text="Normal Mode"
        />

    <RadioButton
        android:id="@+id/radio_random"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onRadioButtonClicked"
        android:text="Random Mode" />
    </RadioGroup>

Remember, all of that stuff went in-between the RelativeLayout tags. Ok, now we’re ready for the Kotlin code.

onCreate function

You will probably need to add a snippet of code to your app’s build.gradle file so you can “bind” your Kotlin code to the layout file. Be careful – there are two of these files. You want the one that is inside “app” directory, not the one that’s in the root directory. In build.gradle, in the android block, paste this snippet and sync gradle:

buildFeatures {
    viewBinding = true
}

Next let’s write our code in the onCreate function that’s given to us by Android Studio:

class MainActivity : AppCompatActivity() {

    var mode: String = "normal" //represents what radio button user selected

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

        val binding = ActivityMainBinding.inflate(layoutInflater) //bind to layout file
        setContentView(binding.root)

        val button = binding.buttonStart //get the start button
        button.setOnClickListener {
            val theIntent = Intent(this, TableActivity::class.java)
            var table = binding.edittextTimestable.text.toString() // get what table the user entered
            if (table == "") {
                table = "0" //if the user entered nothing, meaning all tables, set to 0 so toInt() won't fail.
            }
            theIntent.putExtra("mode", mode) // send mode to next screen
            theIntent.putExtra("table", table) // send table to next screen
            startActivity(theIntent)
        }
    }
}

I’ve created a global variable (I believe the Kotlin word is “property”) called mode to hold what radio button the user selected. The Intent stuff is just standard boilerplate code to send the user to the next screen. The next screen’s activity will be called TableActivity, which this bit Intent(this, TableActivity::class.java) has TableActivity in it.

You’ll notice we’ve attached mode and table to the intent so the next screen’s code can access it. You can see where table is retrieved and set, but you might be wondering how mode is set. We’ll do that next.

onRadioButtonClicked function

I took this code directly from the Android Studio documentation, and substituted my radio button id’s and mode property. We specified the onRadioButtonClicked function in the Radio Button XML code earlier.

fun onRadioButtonClicked(view: View) {
    if (view is RadioButton) {
        // Is the button now checked?
        val checked = view.isChecked

        // Check which radio button was clicked
        when (view.getId()) {
            R.id.radio_normal ->
                if (checked) {
                    this.mode = "normal"
                }
            R.id.radio_random ->
                if (checked) {
                    this.mode = "random"
                }
        }
    }
}

This basically just runs some logic to see which button is clicked, and then set the value of mode.

Try it out!

The app looks pretty good so far!

On the next post – I’ll build the screen where the user can actually practice times tables. Happy coding!

Check out part 2!