Your First Kotlin Android App: An App From Scratch

Aug 15 2023 · Kotlin 1.8.20, Android 13, Android Studio Flamingo | 2022.2.1

Part 2: Manage Data in Jetpack Compose

16. Work with Strings

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 15. Learn About State Hoisting Next episode: 17. Challenge: Create a Custom Composable

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 16. Work with Strings

It’s time to tackle the next item on our programming to-do list: “Read the value of the slider after the user presses the Hit Me button.” But before you do that, I want to tell you about a very important data type you’ll use in your Android apps: “Strings”. You’ve already used this when working with the Text composable but let’s go a bit further.

To create a String in kotlin, you simply surround some text with double quotes. Now, behind the scenes, strings are just a sequence of characters. You can imagine them as a bunch of characters hanging on a piece of string, like you see here.

Strings in Kotlin have a cool feature called string templates also known as string interpolation in other programming languages. That’s just a fancy way of saying that you can put placeholder values inside your strings. And these placeholders will be replaced dynamically when the app runs.

Imagine you’d like to insert a dynamic value into a string at runtime. For example, maybe you want to say “Hello”, and then the name of the user of the app. To accomplish this, you simply put a dollar sign in front of the variable inside the string. In this example, if name is set to Joe, at runtime the string will become “Hello, Joe!”.

OR you can use an expression. You just wrap the expression inside curly braces and put a dollar sign in front of it. The expression is evaluated at runtime and returns the string in this case: 2 plus 2 equals 4.

First, I’m going to show you how to work with string templates in Kotlin. After that, I’ll show you how to format strings when working with string resources.

Open up ResultDialog.kt file. Scroll down to the text argument of the AlertDialog. Currently, the text is gotten from the string resource.

Copy the text argument line. Then convert the current text code into a comment by clicking on that line and press Cmd + /. You can see that double forward slashes are added to that line and it turns grey. Comments are useful in programming. They can be used to describe some code you write or they can be used to temporarily exclude code that you can add back later.

The Kotlin environment would skip the comments when the file is being executed. Using comments is better than deleting the code and trying to remember it when you need it again.

Alright, go ahead and paste the code you copied below the comment and update it to the following:

text = { Text("The slider's value is $sliderValue") }

This is a string template and the value of the sliderValue variable will be replaced with the actual value at runtime because it is preceded by a dollar sign.

But we have an error. Take a moment to see if you can figure out what’s wrong.

If you look closely, the sliderValue variable is marked with red and if you hover over it, it says that the reference does not exist in our code. So the ResultDialog composable needs this value and this is very easy to do. We just need to add it to the parameters list and pass it in wherever you call the ResultDialog function.

Add it in like so:

@Composable
fun ResultDialog(
  hideDialog: () -> Unit,
  sliderValue: Int, // New Code
  modifier: Modifier = Modifier
) {
  //...
}

You added a sliderValue and made it an Integer data type. Integers store whole numbers and I know you might be thinking that the sliderValue should be a decimal based value like a Float. But this dialog is just used to display a user-freindly number, plus, later on in the course, you’ll be calculating the points for a game round and you want the score to be a whole number.

Alright, lets head over to the GameScreen composable. Right now we cant pass in the sliderValue because it is a Float datatype. So we need a way to convert the current sliderValue to an Integer. For this, add in the following code below the state objects:

val sliderToInt = (sliderValue * 100).toInt()

First, you multiplied the sliderValue by 100 because we want to make it percentage based, that is, from 1 to a 100%. Then you called the toInt() method of the Float class. This converts this Float value to Int and the fractional part, if any, is rounded down towards zero.

And if you noticed, this time around we use val instead of var. val simply creates a constant and not a variable. A constant cannot be changed. This means that you cannot reassign the sliderToInt constant somewhere down the line. This makes sense because we want this constant to always refer to the converted slider value and nothing else. We dont intend changing the value down the line like the alertIsVisible state object.

Finally, you need to pass this to the ResultDialog because it needs it. Let’s do that now:

ResultDialog(
  hideDialog = { alertIsVisible = false },
  sliderValue = sliderToInt // New Code
)

Go ahead and run your app.

Move the slider and tap the hit me button. And you can see the slider value is displayed on the AlertDialog and you can try this multiple times to see different values.

Now this is how string templates work, but remember, it is recommended to use string resources because of translations based on locales. So head back to the ResultDialog code and you can navigate directly to a definition by holding down the Cmd key then click on the function. This takes you to its definition and this can work for any Kotlin definition like variables, classes and so on.

Scroll to the text argument and comment the current text by hitting Cmd + /. Then uncomment the text argument that uses a string resource by hitting Cmd + / once again.

text = { Text(stringResource(id = R.string.result_dialog_message)) }
//    text = { Text("The slider's value is $sliderValue") }

Next, head over to the result_dialog_message string definition by holding down Cmd once again and click on it. This takes you to the line where it is defined inside the strings.xml file. Currently, it has the string “This is my first pop up” as its value. We need a way to pass the slider value to this string resource.

To do that, update your code to the following:

<string name="result_dialog_message">The slider\'s value is %1$d.</string>

The format that you see here is the placeholder for the number that will be inserted into the string. 1 signifies the position of the item, so if we have another item at some other point in the string then it would be denoted with the number 2. The letter d after the dollar sign signifies the type of value passed. d simply means the placeholder would accept a whole number. As a side note, strings are denoted with s.

Also, if you noticed, we added a backslash before the single quote. This is done to let the xml processor correctly interpret the single quote as it is a special character.

Alright, head back to the ResultDialog composable. Then pass in the sliderValue as the second argument of the stringResource function like so:

text = { Text(stringResource(id = R.string.result_dialog_message, sliderValue)) }

This value will be interpolated into the placeholder for that string in the strings.xml file.

Run your app once again.

And there you have it!!! The slider value is correctly displayed on the AlertDialog.

Everthing looks fine so far. Let’s go ahead and rotate our device by clicking on the rotate button in the emeulator window. Ooopss!!! What just happened? The dialog is dismissed and the slider moves to its default value.

Well, if you look at how we stored our state, we used the remember API. remember doesnt save the state between device configurations changes like a screen rotation and that is why the state is lost and set back to their defaults.

This is not a problem for Bullseye as it is going to be a landscape-only game and you’ll set this up in the follow-up course.

But to retain state between configurations changes, you use rememberSaveable which saves the state in something called a Bundle. For now, just think of a Bundle as one of the ways data is stored in Android.

Alright go ahead and update the states to use this like so:

var alertIsVisible by rememberSaveable { mutableStateOf(false) }
var sliderValue by rememberSaveable { mutableStateOf(0.5f) }

Run your app.

Move the slider, tap the hit me button, then rotate the device once again. And there you have it, the states are retained between device rotations.