Leave a rating/review
Now that we’re done with the UI part, it’s time to increment and display the score in the score board.
One of the key aspects of learning any new language - be it a spoken language or computer language, is repetition. We’ll be doing this a lot in this course to get you used to writing and thinking in Kotlin. Our goal is to show you core techniques that you’ll be using all the time in Android development.
In this case, I’ll be showing you how to increment the score. We’re going to modify the Bullseye app to show the user’s total score at the bottom of the screen. This will be a review of several key things you’ve learned in this course up to this point.
To get started, open your project in progress or download the starter project for this episode and open it up in Android Studio.
Then open up the main activity file. The first thing you’ll do is to add a variable to hold the total score.
Add the following code below the targetValue
variable:
private var totalScore = 0
In here you added a totalScore variable and set it to 0. Next, let’s increment its value whenever the player taps the hit me button. Add the follwoing code inside the click listener of the hit me button:
...
totalScore = totalScore + pointsForCurrentRound()
binding.gameScoreTextView.text = totalScore.toString()
In here, we get the points generated from the pointsForCurrentRound()
function and add them to the total score variable.
With this, whenever the player taps the hits me button, the total score will always increment.
After that, we set the text of the gameScoreTextView to the totalScore.
And we call the toString function on totalScore so that it passes its string value to the text.
Remember, TextView
s only accept strings and not integers.
Otherwise, you’ll get an error.
Now, I know you must be wondering why the totalScore assingment is underlined with a warning. Go ahead and hover on that line so we can see what it says. Android Studio tells us that this expression can be replaced with an operator assignment. So I’ll go ahead and click on the bulb icon. And then select the suggested replacement.
As you can see, we have a shorter expression.
This is called an operator assignment.
In here, the value returned from the pointsForCurrentRound()
function is added to the current value of the totalScore.
This is just a shorther syntax to get the job done.
And if you recall, you used this type of expression in the previous course where you calculated the difference by multiplying the difference by -1
.
But we still have one more error. Hover over it or open up the problems tab to see what it says. It says: “Only safe or non-null asserted calls are allowed on a nullable receiver of type TextView?”
Hmmm…this means that the gameScoreTextView
is now nullable.
Now, what does nullable mean in Kotlin?
The word nullable is gotten from the word null. And null simply means having no value.
Now, let’s relate this back to bullseye.
Inside bullseye, you have two layout files for the main activity:
-
the initial portrait layout
-
and the landscape layout you generated in an earlier episode.
Remember, we stopped working with the portrait layout and focused on the landscape layout since bullseye is a fullscreen landscape based game.
Now notice something from the screenshots on the slide. The portrait layout does not contain the new game controls we added. Those views are only present in the landscape layout file.
This means that when you try to access a view like the gameScoreTextView
object from the main activity,
there is a possibility you would get “no value.”
There is a possibility that the you would get a null value.
Now, let’s relate this back to the Kotlin programming language.
In kotlin, null is used to represent an object reference that doesn’t point to any object.
That is why if you try accessing the gameScoreTextView
, you’ll get a value of null.
Kotlin is designed to make all types to be non-null by default. Because things could go wrong when you try accessing null references.
So Kotlin allows you to make a variable nullable if you know exactly what you’re doing. And it also provides you with operators to do checks in a more concise way.
To make a variable nullable, you simply append a question mark to its type. And that was what Android Studio did for you when you created the landscape layout. It made the new added controls nullable.
And if you look at the problems tab, you’ll see that the textview has a question appended to it.
Now, since Kotlin has given us the freedom to make variables nullable, it also makes sure that we’re responsible free people. And that’s why you have to play by the rules. It gives us some operators to safely access null values.
Let’s work with one of them now.
Back in Android Studio, go to the error, then add in a question mark before the dot operator.
The question mark and the dot is called the safe call operator in Kotlin.
This way, you know that the text property of the textview can only be set to totalScore.toString()
if gameScoreTextView
is not null.
Go ahead and run your app to try it out.
Notice we have a score of zero on the score board. I’ll move the slider and tap the Hit Me button. Cool!!! The score updates as expected. Move the slider once again and tap the hit me button. And this time around, it correctly adds the score.
That’s null safety in a nutshell. Kotlin that makes all variables non-null by default. And if you chose to make a variable nullable, it provides a robust syntax to work with null references.
We also added an extra measure by making the main activity’s orientation to be only landscape.
With this, the main activity would only access the landscape’s gameScoreTextView
when the app is running.
An if you wanted to use both layouts, then you could just add the views in th portrait layout and there would be no need for using the safe call operator.
Notice that the targetTextView’s text didnt need a safe call. This is because it is present in the two layouts which makes it a non-null variable.
The Null safety topic can be unnecessarily over complicated but if you understood what we did in this episode, then you have a good start with working with null references.