Android projects and activities

How a Gradle project is laid out, what the manifest declares, and how an activity moves through its lifecycle.

The files that matter

An Android app is a Gradle project. The root build file configures the build for every module; the app module is the one that produces your APK or App Bundle.

PathWhat lives there
settings.gradle.ktsWhich modules are part of the build
build.gradle.kts (root)Plugin versions, shared repositories
app/build.gradle.ktscompileSdk, minSdk, targetSdk, dependencies
app/src/main/java/Kotlin sources, folders mirror the package name
app/src/main/res/layouts, strings, drawables, themes
app/src/main/AndroidManifest.xmlComponents, permissions, app metadata
app/src/test/ and app/src/androidTest/JVM unit tests and on-device instrumented tests

Two SDK numbers decide what you can use and who can install the app: minSdk is the oldest Android version you support, compileSdk is the API level you compile against. They are independent, and raising minSdk shrinks your audience.

The manifest and the launcher activity

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

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:label="@string/app_name"
        android:theme="@style/Theme.MyApp">

        <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>
  • The MAIN / LAUNCHER intent filter is what puts an icon on the home screen. Exactly one activity should normally carry it.
  • android:exported is mandatory whenever a component has an intent filter on Android 12 and above: true lets other apps start it.
  • Every component you add (activity, service, receiver, provider) must be declared here, or the system will not know it exists.

The activity lifecycle

An activity is created and destroyed by the system, not by your code. Configuration changes such as rotation destroy and recreate it, so anything you want to survive must be kept outside the instance.

CallbackCalled whenTypical use
onCreateActivity is createdInflate the UI, bind state, restore saved state
onStart / onStopIt becomes visible / is hiddenStart or stop observers, analytics
onResume / onPauseIt gains / loses focusResume or pause media, sensors, animations
onDestroyIt is finishing or being recreatedRelease bindings and long-lived references
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val startCount = savedInstanceState?.getInt("count") ?: 0
        setContent { AppScreen(initial = startCount) }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt("count", 3)
    }
}
💡
Never hold an activity in a static field or a long-lived object: the system may recreate it and your reference points at a dead window, leaking the whole view hierarchy. Keep data in a ViewModel and let the UI be disposable.

FAQ

What is the difference between minSdk and targetSdk?
minSdk is the oldest version that can install the app. targetSdk declares which version's behaviour changes you have opted into and is what Google Play requires you to keep current.
Why did my state disappear when I rotated the device?
Rotation recreates the activity by default. Keep state in a ViewModel, or persist what matters in onSaveInstanceState for small, transient values.

Layouts and Jetpack Compose Permissions, storage and publishing

Last refreshed 2026-09-18.