Let's create a simple Android app using Kotlin that will have a single screen where the user can guess a number between 1 and 100.
The app will then generate a random number for the computer and determine who is closer to 50.
The result will be displayed on the screen, and the user will be invited to play again.
1. Project Setup
Gradle Build Scripts
Project-level `build.gradle’
```gradle
// Project level build.gradle (usually located at the root of your project)
buildscript {
ext.kotlin_version = "1.8.0"
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:8.0.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
```
**Module-level `build.gradle`**
```gradle
// Module level build.gradle (usually located in app folder)
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 33
defaultConfig {
applicationId "com.example.guessgame"
minSdkVersion 21
targetSdkVersion 33
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
```
2. Layout File (`activity_main.xml`)
<!-- res/layout/activity_main.xml -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/instructionText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Guess a number between 1 and 100"
android:textSize="18sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="16dp" />
<EditText
android:id="@+id/guessInput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Enter your guess"
android:inputType="number"
app:layout_constraintTop_toBottomOf="@id/instructionText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="16dp"/>
<Button
android:id="@+id/submitGuessButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit Guess"
app:layout_constraintTop_toBottomOf="@id/guessInput"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp" />
<TextView
android:id="@+id/resultText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text=""
android:textSize="18sp"
app:layout_constraintTop_toBottomOf="@id/submitGuessButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="16dp"/>
<Button
android:id="@+id/playAgainButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Play Again"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/resultText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
```
3. Kotlin Code (`MainActivity.kt`)
```kotlin
// src/main/java/com/example/guessgame/MainActivity.kt
package com.example.guessgame
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
private lateinit var instructionText: TextView
private lateinit var guessInput: EditText
private lateinit var submitGuessButton: Button
private lateinit var resultText: TextView
private lateinit var playAgainButton: Button
private var targetNumber = Random.nextInt(1, 101)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
instructionText = findViewById(R.id.instructionText)
guessInput = findViewById(R.id.guessInput)
submitGuessButton = findViewById(R.id.submitGuessButton)
resultText = findViewById(R.id.resultText)
playAgainButton = findViewById(R.id.playAgainButton)
submitGuessButton.setOnClickListener {
val userGuess = guessInput.text.toString().toIntOrNull()
if (userGuess != null) {
playGame(userGuess)
} else {
resultText.text = "Please enter a valid number!"
resultText.visibility = View.VISIBLE
}
}
playAgainButton.setOnClickListener {
resetGame()
}
}
private fun playGame(userGuess: Int) {
val computerGuess = Random.nextInt(1, 101)
val userDelta = kotlin.math.abs(50 - userGuess)
val computerDelta = kotlin.math.abs(50 - computerGuess)
val winner = when {
userDelta < computerDelta -> "User wins! (User: $userGuess, Computer: $computerGuess)"
computerDelta < userDelta -> "Computer wins! (User: $userGuess, Computer: $computerGuess)"
else -> "It's a tie! (User: $userGuess, Computer: $computerGuess)"
}
resultText.text = winner
resultText.visibility = View.VISIBLE
playAgainButton.visibility = View.VISIBLE
}
private fun resetGame() {
guessInput.text.clear()
resultText.text = ""
resultText.visibility = View.GONE
playAgainButton.visibility = View.GONE
targetNumber = Random.nextInt(1, 101)
}
}
```
Explanation
1. Project-level build.gradle
Sets up the Kotlin plugin and repositories for the project.
2. **Module-level build.gradle**:
Configures Android-specific settings and dependencies for the app.
3. **activity_main.xml**:
Defines the UI layout for the main screen, including the instruction text, input field, submit button, result text, and play again button.
4. **MainActivity.kt**:
- Initializes UI elements and sets click listeners for buttons.
- Handles user input validation and game logic.
- Determines the winner based on who is closer to 50.
- Resets the game when the user chooses to play again.
This lab provides straightforward example of building an Android app with basic UI interactions and game logic.
Let's break it down with an illustrative example of how the MainActivity.kt connects to and interacts with the layout activity_main.xml.
Lecture: Connecting MainActivity.kt with activity_main.xml
In Android development, the Activity class serves as the entry point for interacting with the user. It's where you place the logic to control what the user sees and how they can interact with your app. The layout file (activity_main.xml) defines the user interface (UI) elements.
Step-by-Step Breakdown
Setting Up the Layout in MainActivity When an activity is created, it needs to be associated with a layout. This is done using the setContentView method in the onCreate method of the Activity class.
kotlinCopy codeoverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)}
Here, R.layout.activity_main refers to the activity_main.xml layout file in the res/layout directory.
To interact with UI elements defined in the layout file, we use findViewById to get references to these elements.
kotlinCopy code// Declaring UI elementsprivate lateinit var instructionText: TextViewprivate lateinit var guessInput: EditTextprivate lateinit var submitGuessButton: Buttonprivate lateinit var resultText: TextViewprivate lateinit var playAgainButton: Button
Within the onCreate method, we initialize these elements by their IDs as specified in the XML layout file.
kotlinCopy codeinstructionText = findViewById(R.id.instructionText)guessInput = findViewById(R.id.guessInput)submitGuessButton = findViewById(R.id.submitGuessButton)resultText = findViewById(R.id.resultText)playAgainButton = findViewById(R.id.playAgainButton)
Setting Up Click Listeners To make the buttons functional, we set click listeners on them.
kotlinCopy codesubmitGuessButton.setOnClickListener { val userGuess = guessInput.text.toString().toIntOrNull() if (userGuess != null) { playGame(userGuess) } else { resultText.text = "Please enter a valid number!" resultText.visibility = View.VISIBLE }}
playAgainButton.setOnClickListener { resetGame()}
Define the methods that handle the game logic.
playGame(userGuess: Int): Compares the user's guess with a randomly generated computer guess and determines the winner. resetGame(): Resets the game state for a new round. kotlinCopy codeprivate fun playGame(userGuess: Int) { val computerGuess = Random.nextInt(1, 101) val userDelta = kotlin.math.abs(50 - userGuess) val computerDelta = kotlin.math.abs(50 - computerGuess)
val winner = when { userDelta < computerDelta -> "User wins! (User: $userGuess, Computer: $computerGuess)" computerDelta < userDelta -> "Computer wins! (User: $userGuess, Computer: $computerGuess)" else -> "It's a tie! (User: $userGuess, Computer: $computerGuess)" }
resultText.text = winner resultText.visibility = View.VISIBLE playAgainButton.visibility = View.VISIBLE}
private fun resetGame() { guessInput.text.clear() resultText.text = "" resultText.visibility = View.GONE playAgainButton.visibility = View.GONE}
Illustrative Example Code
To make it more concrete, here’s the complete MainActivity.kt code again with comments for clarity:
kotlinCopy code// src/main/java/com/example/guessgame/MainActivity.ktpackage com.example.guessgame
import android.os.Bundleimport android.view.Viewimport android.widget.Buttonimport android.widget.EditTextimport android.widget.TextViewimport androidx.appcompat.app.AppCompatActivityimport kotlin.random.Random
class MainActivity : AppCompatActivity() {
// Declaring UI elements private lateinit var instructionText: TextView private lateinit var guessInput: EditText private lateinit var submitGuessButton: Button private lateinit var resultText: TextView private lateinit var playAgainButton: Button
// Random number for the game private var targetNumber = Random.nextInt(1, 101)
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)
// Initializing UI elements instructionText = findViewById(R.id.instructionText) guessInput = findViewById(R.id.guessInput) submitGuessButton = findViewById(R.id.submitGuessButton) resultText = findViewById(R.id.resultText) playAgainButton = findViewById(R.id.playAgainButton)
// Setting up click listener for the submit button submitGuessButton.setOnClickListener { val userGuess = guessInput.text.toString().toIntOrNull() if (userGuess != null) { playGame(userGuess) } else { resultText.text = "Please enter a valid number!" resultText.visibility = View.VISIBLE } }
// Setting up click listener for the play again button playAgainButton.setOnClickListener { resetGame() } }
// Method to handle the game logic private fun playGame(userGuess: Int) { val computerGuess = Random.nextInt(1, 101) val userDelta = kotlin.math.abs(50 - userGuess) val computerDelta = kotlin.math.abs(50 - computerGuess)
val winner = when { userDelta < computerDelta -> "User wins! (User: $userGuess, Computer: $computerGuess)" computerDelta < userDelta -> "Computer wins! (User: $userGuess, Computer: $computerGuess)" else -> "It's a tie! (User: $userGuess, Computer: $computerGuess)" }
resultText.text = winner resultText.visibility = View.VISIBLE playAgainButton.visibility = View.VISIBLE }