RizTech Academy logo
RizTech Academy
Getting StartedLesson 3 of 530 min

Your first app, running

There is a particular satisfaction in seeing your own words on a phone screen, and it is worth getting there before learning anything else. This lesson creates the Mandi Bhav project, makes it match the course's starter exactly, explains the one decision you make at creation that is hard to undo later, and runs it.

Create the project

From the Welcome screen click New Project, or from inside an open project use File → New → New Project.

  1. Under Phone and Tablet, choose Empty Activity. It is the Compose template: one screen, with Compose and Material 3 already set up. Templates with "Views" in the name use the older XML toolkit, and are not what you want.
  2. Fill in the configuration page:
Field Value Why
Name Mandi Bhav What appears under the launcher icon. You can change it later.
Package name com.riztechacademy.mandibhav Becomes your application ID, the app's identity on every phone and on Google Play. Effectively permanent once published.
Save location A folder you will find again On a Mac, avoid Desktop, Documents and Downloads: macOS privacy protection can stop Android Studio seeing the files.
Minimum SDK API 26 (Android 8.0) The oldest Android version the app will install on. Explained below.
Build configuration language Kotlin DSL, if the wizard asks Build files in Kotlin (.kts), as in this course.

The package name is written backwards from a domain you control, so that two companies' apps can never collide. If you have no domain, com.yourname.mandibhav is fine for learning; know that once an app is on Google Play, changing it means publishing a different app.

  1. Click Finish. Android Studio creates the files and runs a Gradle sync: it downloads the build tools and libraries the project needs and works out how to build it. The first time, on a fresh machine, this takes minutes rather than seconds. The first full build of this project on the course's machine took about a minute and twenty seconds; later builds take a few seconds. Leave it alone until the progress bar at the bottom of the window finishes.

Make it match the course starter

The wizard's output changes from one Android Studio release to the next: different library versions, sometimes extra files. The course needs everyone on the same project, so now you make yours match. This is also your first lesson in not trusting generated code blindly.

MainActivity.kt

Open app/src/main/java/com/riztechacademy/mandibhav/MainActivity.kt (the folder is called java even though it holds Kotlin; some versions of the template call it kotlin) and replace its contents with this. Type it rather than pasting it; your fingers learn the shape of an Android file that way.

package com.riztechacademy.mandibhav

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            MaterialTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Greeting(name = "Mandi Bhav", modifier = Modifier.padding(innerPadding))
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(text = "Namaste from $name", modifier = modifier)
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Greeting("Mandi Bhav")
    }
}

Against the template, three things changed: the greeting now says "Namaste from" instead of "Hello", it greets "Mandi Bhav" instead of "Android", and the content is wrapped in the plain MaterialTheme instead of a theme the wizard generated for you. Your own theme comes back, built properly, in the theming module.

Read it top to bottom once, without trying to master it:

  • class MainActivity : ComponentActivity(): an activity is a screen the system can start. This one is the app's entry point; module 2 explains why most modern apps have exactly one.
  • onCreate: Android calls this when it creates the activity. You did not call it and never will. That inversion, the system calling you, is the heart of Android.
  • enableEdgeToEdge(): lets the app draw behind the status bar and navigation bar.
  • setContent { ... }: hands the screen over to Compose. Everything inside is a description of the UI.
  • Scaffold gives a standard screen structure and passes innerPadding: the space taken by the system bars, which your content must stay out of.
  • @Composable fun Greeting: a composable function, a piece of UI. It takes data (name) and describes what to show.
  • @Preview: renders GreetingPreview in the editor's design pane without running the app.

The build files

Open app/build.gradle.kts and make it read exactly:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace = "com.riztechacademy.mandibhav"
    compileSdk {
        version = release(37) {
            minorApiLevel = 2
        }
    }

    defaultConfig {
        applicationId = "com.riztechacademy.mandibhav"
        minSdk = 26
        targetSdk = 36
        versionCode = 1
        versionName = "0.1"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    buildFeatures {
        compose = true
    }
}

dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.compose.ui)
    implementation(libs.androidx.compose.ui.graphics)
    implementation(libs.androidx.compose.ui.tooling.preview)
    implementation(libs.androidx.compose.material3)
    debugImplementation(libs.androidx.compose.ui.tooling)
    testImplementation(libs.junit)
}

The libs. names come from gradle/libs.versions.toml, the version catalog. Make it read:

[versions]
agp = "9.5.1"
kotlin = "2.4.21"
coreKtx = "1.19.1"
activityCompose = "1.13.0"
lifecycle = "2.11.0"
composeBom = "2026.09.00"
junit = "4.13.2"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
junit = { group = "junit", name = "junit", version.ref = "junit" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

And the top-level build.gradle.kts (the one next to settings.gradle.kts, not inside app/):

plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.compose) apply false
}

If your wizard added an org.jetbrains.kotlin.android plugin anywhere, remove it. From Android Gradle Plugin 9, Kotlin support is built in and that plugin is no longer applied; only the Compose compiler plugin remains.

The manifest, and the leftovers

Make app/src/main/AndroidManifest.xml read:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.Material.Light.NoActionBar">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Then delete what nothing uses any more: the ui.theme package next to MainActivity.kt, the themes.xml file under res/values, and the test and androidTest folders under app/src (the testing module creates them again). Leave the launcher icons, strings.xml and colors.xml alone; yours may look slightly different from the course's and that is harmless.

After editing build files, Android Studio shows a banner offering to sync. Click Sync Now. A sync that ends without red text means your project now matches the course.

Choosing minSdk: a trade-off, not a default

Three numbers in that build file look alike and mean different things:

Setting Here Meaning
compileSdk 37.2 Which Android API you compile against: the newest one you can call. The platform from lesson 2.
targetSdk 36 Which Android version's behaviour you have tested against. Newer phones apply newer rules only once you raise it.
minSdk 26 The oldest Android version that can install the app at all.

minSdk is the one with consequences for real people. Android 8.0 (API 26) came out in 2017. Every phone on Android 7 or earlier cannot install Mandi Bhav, and Google Play will not even show it to them. That is the cost, stated plainly: some of Arjun's neighbours, on the oldest phones, are excluded. If you sideload the APK onto such a phone anyway, the install is refused. Here is the same refusal produced the other way round, with minSdk set to 37 and installed on an Android 16 (API 36) emulator:

adb: failed to install app-debug.apk: Failure [INSTALL_FAILED_OLDER_SDK: Requires newer sdk version #37 (current version is #36)]

Why accept it? Because going lower is not free either, and below a point it is not possible. Here is what the build does with lower values, on this exact project. With minSdk = 21:

> Manifest merger failed : uses-sdk:minSdkVersion 21 cannot be smaller than version 23 declared in
  library [androidx.navigationevent:navigationevent-android:1.0.0] ... as the library might be using
  APIs not available in 21

The libraries themselves need API 23. With minSdk = 25:

> Android resource linking failed
  com.riztechacademy.mandibhav.app-main-35:/mipmap-anydpi/ic_launcher.xml: error: <adaptive-icon>
  elements require a sdk version of at least 26.

The launcher icon uses adaptive icons, which arrived in API 26. You could keep a second set of old-style icons for API 23 to 25, and then you would also be maintaining workarounds for java.time (the modern date API, which arrived in 26 and which a price-per-date app uses everywhere) and for notification channels (also 26, needed for price alerts). Every API level you support is a version you must test on, and the oldest phones are the slowest and least memory-rich. API 26 is the trade this course makes: the oldest phones excluded, in return for less code and fewer untestable paths. For your own apps, the wizard's Help me choose link shows the current share of devices on each version; make the decision with that open, and write down why.

Run it

At the top of the window is the device menu, and next to it the green Run button (Shift + F10 on Windows and Linux, Ctrl + R on a Mac). Pick a device and press Run. If the menu is empty, you have no virtual device yet: create one as the end of the installation lesson describes, then come back.

Android Studio builds the APK, installs it and starts MainActivity. You should see "Namaste from Mandi Bhav" in the top-left corner, immediately below the status bar.

The same thing from a terminal, in the project folder, shows what Run does for you. (adb lives in the SDK's platform-tools folder; lesson 4 puts it on your path. On Windows, use gradlew.bat instead of ./gradlew.)

./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -W -n com.riztechacademy.mandibhav/.MainActivity

On an emulator, the real output of the last command was:

Starting: Intent { cmp=com.riztechacademy.mandibhav/.MainActivity }
Status: ok
LaunchState: COLD
Activity: com.riztechacademy.mandibhav/.MainActivity
TotalTime: 722
WaitTime: 726
Complete

LaunchState: COLD means the app's process did not exist and Android started it from nothing. TotalTime: 722 is milliseconds until the first frame was drawn. Remember this number: it is from a fast emulator on a fast laptop, and lesson 4 explains why your users will not see it.

The trap: padding you thought you could skip

Modifier.padding(innerPadding) looks like decoration. Delete it, so the line reads Greeting(name = "Mandi Bhav", modifier = Modifier), and run again. The text now sits on top of the clock and battery icons in the status bar. enableEdgeToEdge() let you draw under the system bars; innerPadding is how Scaffold tells you where they are. Skip it and your content collides with the system on every phone. Put it back. Edge-to-edge gets its own lesson in the layout module.

Check your work

What does the package name become, and why is it hard to change? The application ID, the app's identity on devices and on Google Play. Changing it after publishing means a different app.

Which method does Android call when it creates your screen? onCreate.

What is the difference between compileSdk and minSdk? compileSdk is the API you compile against; minSdk is the oldest version that can install the app.

Why can this project not use minSdk 21? A library it depends on declares minSdk 23, so the manifest merger fails.

What did minSdk 26 buy, and what did it cost? Adaptive icons, java.time and notification channels without workarounds, and fewer versions to test; phones on Android 7 and older cannot install the app.

What does TotalTime in am start -W measure? Milliseconds from the launch request to the first frame drawn.

Practice

  1. Create the project and make it match the course starter as above. Build it with no errors.
  2. Run it and see "Namaste from Mandi Bhav".
  3. Change the name passed to Greeting to your own town and run again. Then put it back.
  4. Open the design pane on MainActivity.kt and find the preview. Change the text and watch the preview update without running the app.
  5. Break it on purpose: change Text( to Txt( and build. Read the first line of the error, which names the file, the line and Unresolved reference 'Txt'. Fix it.
  6. Break it again: delete the closing " of "Namaste from $name" and read the error. The compiler reports Expecting '"' at the exact column. Fix it.
  7. Harder: set minSdk = 25, sync and build. Read the adaptive-icon error, explain in one sentence why it happens, and restore 26. Then run the three terminal commands above and compare your TotalTime with 722.

Official documentation

  • Create a project — The New Project wizard field by field, including the Help me choose chart for minimum API level.
  • Create your first Android app — Google's own walk-through of the Empty Activity template, useful for comparing against what your wizard generated.
  • The uses-sdk element — What minSdk, targetSdk and compileSdk mean to the system, with the table of API levels and Android version names.
  • Build and run your app — What the Run button does, run configurations, and Apply Changes.

Next: the emulator, and running Mandi Bhav on your own phone.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Selected students who finish a course can join our internship, with real-world projects and code review from a working engineer.

About the internship