> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modaal.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How Android Apps Work: Anatomy of a Modern Android App

> An Android app is an APK or app bundle: a manifest declaring entry points, Jetpack Compose screens driven by state holders, and a Gradle build behind it.

An Android app is a signed package — an APK, or an app bundle that Google Play turns into APKs — holding a manifest that tells the system where the app starts, compiled Kotlin code whose screens are functions that turn state into UI, and the resources the app draws on. This page walks that anatomy for readers who build software but haven't built for Android: what is in the package, where code starts running, how a screen is drawn, where the logic lives, and how the finished app reaches users. Each section links the page of [Google's developer documentation](https://developer.android.com/guide/components/fundamentals) that treats it in full.

<Frame caption="The chain inside every modern Android app: the manifest declares the entry activity, the activity sets a composable tree as its content, state flows in from a state holder, and long-running work is handed off to services.">
  <img src="https://mintcdn.com/modaal/JvQq_HlyMqkJyZGb/images/android-app-anatomy-diagram.svg?fit=max&auto=format&n=JvQq_HlyMqkJyZGb&q=85&s=9afb1585116f9e8c1f5827a66b4cb8ef" alt="Block diagram of a modern Android app: AndroidManifest.xml declares MainActivity, which sets the Jetpack Compose composable tree as its content; state flows from a state holder to the composables and events flow back; services and background workers handle work that outlives the screen" width="920" height="440" data-path="images/android-app-anatomy-diagram.svg" />
</Frame>

## What is inside an Android app?

The artifact users install is an **APK** — a signed archive of compiled code, resources (icons, strings, themes), and native libraries. What developers upload to Google Play is usually an **[app bundle](https://developer.android.com/guide/app-bundle)** (`.aab`), from which Play generates a smaller APK tailored to each device's screen density, CPU architecture, and language.

At the root of the package sits **[AndroidManifest.xml](https://developer.android.com/guide/topics/manifest/manifest-intro)**. It names the app, lists every entry point the system may launch, and declares the permissions the app requests — camera, location, notifications. Android reads the manifest before running any of the app's code, so nothing undeclared can be launched or granted.

## Where does an Android app start? The entry points

There is no single `main()` function to look for. The system starts an app at whichever declared entry point the situation calls for, and the manifest lists them all.

An **[Activity](https://developer.android.com/guide/components/activities/intro-activities)** is the entry point for anything the user sees. When someone taps the app's icon, Android launches the activity the manifest marks as the launcher — conventionally named `MainActivity` — and hands it a window to fill. A modern app typically has one activity hosting every screen, switching between them in code.

The **[Application class](https://developer.android.com/reference/android/app/Application)** is instantiated before any activity, once per process. Apps use it for initialization that everything else depends on — logging, dependency wiring, crash reporting.

**[Broadcast receivers](https://developer.android.com/guide/components/broadcasts)** are entry points with no UI at all: the system invokes them when an event they registered for occurs — the device finished booting, connectivity changed, an alarm fired — even if the app isn't running.

## How is a screen drawn? Jetpack Compose

Screens are written in **[Jetpack Compose](https://developer.android.com/develop/ui/compose/mental-model)**, Google's recommended toolkit for native UI: a screen is a [Kotlin](https://developer.android.com/kotlin) function annotated `@Composable` that describes what to show for the current state. When the state changes, the framework re-runs the affected functions and updates only what differs — the developer never mutates the screen by hand. A minimal but complete app:

```kotlin theme={null}
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { CounterScreen() }
    }
}

@Composable
fun CounterScreen() {
    var count by remember { mutableIntStateOf(0) }
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
        modifier = Modifier.fillMaxSize(),
    ) {
        Text("Taps: $count", style = MaterialTheme.typography.headlineMedium)
        Button(onClick = { count++ }) { Text("Tap me") }
    }
}
```

(Imports omitted.) The activity's one job here is `setContent` — everything visible is the composable tree.

Search results will also surface the older layer: **XML layout files** inflated into a tree of `View` objects, edited through code. That system still runs in production apps and in most tutorials written before Compose, which is why both appear when you search — but a new project's screens are Compose functions.

## Where does the app's logic live?

Logic lives in a **state holder**: a class that owns a screen's state, exposes it as an observable value, and updates it in response to events from the UI — the pattern Google's [app architecture guide](https://developer.android.com/topic/architecture) recommends, with Jetpack's `ViewModel` as the common implementation. State flows one way, from the holder down into the composable tree; events flow back up as function calls. The payoff is that a screen's behavior can be exercised in a plain unit test — construct the state holder, send it events, assert on the state — with no device attached.

## What runs in the background?

Work that must outlive the screen — uploads, sync, media playback — runs through the platform's [background-work facilities](https://developer.android.com/develop/background-work/background-tasks): scheduled workers for deferrable jobs, and foreground services for work the user is actively aware of, which must show a notification. Android decides when deferred work actually runs, batching it around battery and network conditions, so apps request work rather than simply spawning threads that the system may kill.

## How is an Android app built? Gradle

Every Android app is built by **[Gradle](https://developer.android.com/build)**, driven by build files checked into the project — there is no IDE-owned project file that the build depends on. The `build.gradle.kts` of the app module declares the app's identity and its platform window:

```kotlin theme={null}
android {
    namespace = "dev.example.counter"
    compileSdk = 36

    defaultConfig {
        applicationId = "dev.example.counter"
        minSdk = 26
        targetSdk = 36
    }
}
```

Three numbers define that window: `compileSdk` is the API the code compiles against, `minSdk` is the oldest Android version the app installs on, and `targetSdk` declares which version's behavior rules the app has been tested for. What each API level corresponds to, and how many devices each `minSdk` choice reaches, is the whole subject of [Android API levels: versions, codenames, and device coverage](/articles/android-api-levels).

## Where do you run it? Devices and emulators

Development runs on a real device over USB or on the **[Android Emulator](https://developer.android.com/studio/run/emulator)** — a virtual device booted from a system image of a chosen API level, defined by an AVD ("Android Virtual Device") profile such as a Pixel 8 running API 36. The emulator runs the same system the phone does, so the app, its background workers, and its notifications behave as on hardware. On a Mac, one setup pass installs the SDK, a JDK, and a first emulator — [Set up the Android toolchain](/guides/setup-android) documents it.

<Frame caption="The counter app from this page, built with Gradle and installed on a Pixel 8 emulator running API level 36.">
  <img src="https://mintcdn.com/modaal/iDPs8kgTc8SU8dMF/images/android-emulator-counter.png?fit=max&auto=format&n=iDPs8kgTc8SU8dMF&q=85&s=ee160bf3c360617a3360b55e45d98c8b" alt="Android emulator screen showing the Compose counter app: a status bar, the text Taps: 7, and a Tap me button" style={{ width: "280px" }} width="540" height="1200" data-path="images/android-emulator-counter.png" />
</Frame>

## How does an app reach users?

Through **Google Play**: the developer uploads the app bundle, and Play verifies, signs, and distributes per-device APKs. With [Play App Signing](https://developer.android.com/studio/publish/app-signing), Google holds the signing key and every update must come from the same developer account — devices refuse an update whose signature doesn't match the installed app. Play also enforces [a floor on `targetSdk`](https://developer.android.com/google/play/requirements/target-sdk) for new submissions and updates, so shipped apps track recent platform behavior.

## Common questions

<AccordionGroup>
  <Accordion title="What's the difference between an APK and an app bundle?" icon="box">
    An APK is what a device installs and runs. An app bundle (`.aab`) is what a developer uploads to Google Play: a superset package from which Play builds a smaller APK per device configuration. Outside Play — a local build, a direct download — you deal in APKs.
  </Accordion>

  <Accordion title="Is an Activity the same thing as a screen?" icon="mobile-screen">
    Not anymore, as a rule. An Activity is the entry point that owns a window; a modern app has one activity, and its screens are composable functions the app navigates between inside that window. Apps built earlier often used one activity per screen, and both designs run fine today.
  </Accordion>

  <Accordion title="Do I still need to learn XML layouts?" icon="code">
    Only to read existing code and older tutorials. New screens are written in Jetpack Compose — Kotlin functions, no XML. The XML `View` system remains supported, and large apps commonly contain both while newer screens accumulate in Compose.
  </Accordion>

  <Accordion title="Are Android apps written in Kotlin or Java?" icon="language">
    Kotlin. Android's own APIs, documentation, and tooling are [Kotlin-first](https://developer.android.com/kotlin), and Compose is Kotlin-only. Java remains fully supported for existing code, so long-lived apps often carry both languages.
  </Accordion>

  <Accordion title="Can I build Android apps on a Mac?" icon="apple">
    Yes — the SDK, the emulator, and the JDK all run natively on macOS, alongside Xcode. [Set up the Android toolchain](/guides/setup-android) walks through the one-banner install Modaal provides.
  </Accordion>
</AccordionGroup>

<Note>
  [Modaal](https://modaal.dev) builds the apps this page describes without you assembling the toolchain yourself; [Set up the Android toolchain](/guides/setup-android) covers what it installs.
</Note>

## Sources and further reading

* [Application fundamentals](https://developer.android.com/guide/components/fundamentals) — Google's overview of apps, components, and the manifest
* [Introduction to activities](https://developer.android.com/guide/components/activities/intro-activities) — the entry-point contract in full
* [Thinking in Compose](https://developer.android.com/develop/ui/compose/mental-model) — the state-driven UI model
* [Guide to app architecture](https://developer.android.com/topic/architecture) — state holders and unidirectional data flow
* [Background work overview](https://developer.android.com/develop/background-work/background-tasks) — workers, services, and when each applies
* [Configure your build](https://developer.android.com/build) — the Gradle build system for Android
* [About Android App Bundles](https://developer.android.com/guide/app-bundle) — the publishing format
* [App signing](https://developer.android.com/studio/publish/app-signing) — how Play signs and verifies releases

## Read next

<CardGroup cols={2}>
  <Card title="Android API levels and device coverage" icon="table" href="/articles/android-api-levels">
    Every Android version with its API level and codename, live device-coverage numbers, and how to choose a minSdk.
  </Card>

  <Card title="The Duet framework" icon="mobile-screen" href="/articles/duet">
    iOS and Android from one shared core: feature logic written once, native SwiftUI and Jetpack Compose interfaces, and a CI gate that keeps the two apps in agreement.
  </Card>

  <Card title="Kotlin Multiplatform Android app structure" icon="folder-tree" href="/articles/duet-android-app-anatomy">
    This page's anatomy, applied: what a Duet-built Android app puts in each module, shown on a shipped app.
  </Card>

  <Card title="How to build testable Android apps" icon="vial-circle-check" href="/articles/testable-android-apps">
    What a fixed architecture buys over a blank project: pure reducers, effects as data, and recorded behavior tests.
  </Card>
</CardGroup>
