Activity Basics: Der Einstiegspunkt deiner Compose-App
Wie eine Activity in einer Compose-first-App funktioniert: Einstiegspunkt, Lebenszyklus und Single-Activity-Architektur kompakt erklärt.
Wenn du mit Android startest, stolperst du sehr früh über den Begriff Activity. In modernen Compose-Projekten siehst du meist nur eine einzige Datei namens MainActivity.kt und fragst dich, warum das überhaupt nötig ist, wenn doch alle Bildschirme als Composables gebaut werden. Genau diese Lücke schließt dieser Artikel: Du lernst, was eine Activity wirklich ist, wie sie sich in einer Compose-first-App verhält und worauf du beim Lebenszyklus achten musst, damit dein UI stabil bleibt.
Was ist das?
Eine Activity ist eine vom Android-System verwaltete Komponente, die einen einzelnen, fokussierten Bildschirm deiner App repräsentiert. Sie ist gleichzeitig dein Einstiegspunkt: Wenn ein Nutzer dein App-Icon antippt, startet das System genau die Activity, die du im Manifest mit dem Intent-Filter MAIN und LAUNCHER markiert hast. Ohne diese Activity hat dein Prozess kein Fenster und kein UI.
Du kannst dir eine Activity als Brücke zwischen Betriebssystem und deiner UI-Welt vorstellen. Das System hält die Activity in einem Backstack, weist ihr ein Fenster zu, leitet Touch-Events weiter und entscheidet, wann sie sichtbar, pausiert oder gestoppt wird. Innerhalb dieses Fensters bist du frei: Du kannst klassische Views, Fragmente oder eben einen Compose-Baum platzieren.
In einer Compose-first-App verschiebt sich der Fokus stark. Früher hatte fast jeder Bildschirm seine eigene Activity, was viel Boilerplate, komplizierte Navigationen und harte Übergaben über Intent-Extras bedeutete. Heute ist die etablierte Architektur die Single-Activity-App: Eine einzige Activity hostet deinen Composable-Baum, und die Navigation zwischen Bildschirmen passiert innerhalb von Compose, etwa mit Navigation Compose. Die Activity wird dadurch zum dünnen Rahmen, der sich um Plattform-Themen wie Theming, Edge-to-Edge-Darstellung, Berechtigungen und Lebenszyklus kümmert, während die fachliche UI in Composables und ViewModels lebt.
Diese Trennung ist wichtig, weil sie dir Klarheit über Verantwortlichkeiten gibt. Plattform-nahe Aufgaben gehören in die Activity oder in eng angebundene Hilfsklassen. Bildschirm-Logik und UI-State gehören in Composables und ViewModels. Wenn du das verinnerlichst, vermeidest du eine ganze Klasse von Bugs, die entstehen, weil Activity und UI-Logik durcheinanderlaufen.
Wie funktioniert es?
Jede Activity erbt von ComponentActivity (oder einer ihrer Subklassen wie AppCompatActivity). Beim Start ruft das System eine feste Reihenfolge von Lebenszyklus-Methoden auf, die du überschreiben kannst. Die wichtigsten sind:
onCreate(savedInstanceState)— wird genau einmal pro Activity-Instanz aufgerufen. Hier konfigurierst du dein UI mitsetContent { ... }und legst Dinge an, die für die gesamte Lebensdauer dieses Fensters gelten.onStart()— die Activity wird für den Nutzer sichtbar, ist aber noch nicht im Vordergrund.onResume()— die Activity ist im Vordergrund und reagiert auf Eingaben. Hier startest du Ressourcen, die nur sichtbar Sinn ergeben, etwa Sensoren oder Kamera-Previews.onPause()— etwas verdeckt die Activity teilweise (zum Beispiel ein transparenter Dialog). Stoppe hier alles, was im Vordergrund laufen muss.onStop()— die Activity ist nicht mehr sichtbar. Schließe Datenbank-Cursor, lange Streams oder Broadcast-Receiver, die nur im sichtbaren Zustand benötigt werden.onDestroy()— die Activity wird endgültig zerstört, etwa durch Drücken der Zurück-Taste oder durch eine Konfigurationsänderung.
Ein zentrales Konzept sind Konfigurationsänderungen: Wenn der Nutzer das Gerät dreht, das Theme wechselt oder die Sprache umstellt, zerstört Android die Activity standardmäßig und erstellt sie neu. Das klingt erst einmal aggressiv, sorgt aber dafür, dass deine UI sauber neu aufgebaut wird. Damit dabei kein State verloren geht, gibt es zwei Werkzeuge, die du kennen musst:
rememberSaveablein Compose speichert kleine UI-States (etwa Texte in Eingabefeldern oder Scroll-Positionen) automatisch überBundle-Mechanismen.ViewModelüberlebt Konfigurationsänderungen komplett und ist der richtige Ort für ladbare Daten, Netzwerkergebnisse oder komplexere Bildschirm-Logik.
Der Activity-Backstack ist ein weiteres Konzept, das du im Hinterkopf behalten solltest. Wenn du in einer Single-Activity-App bleibst, ist dieser Stack meist leer bis auf deine eine Activity, und Navigation passiert intern. Sobald du jedoch eine zweite Activity startest oder ein Intent an eine andere App sendest, wächst der Stack, und die Lebenszyklus-Aufrufe verschachteln sich. Auch deshalb empfiehlt Google für neue Apps die Single-Activity-Variante: weniger Backstack-Magie, klarere Datenflüsse.
Ein Detail, das oft missverstanden wird: Composables haben einen eigenen Lebenszyklus, der innerhalb der Activity läuft. Ein Composable kann mehrfach pro Sekunde neu komponiert werden, während die Activity dieselbe bleibt. Verwechsle diese beiden Ebenen nicht. Ressourcen, die an die Activity gebunden sind (Fenster, System-Services), gehören in die Activity-Methoden. Logik, die zum UI-State passt, gehört in LaunchedEffect, DisposableEffect oder ein ViewModel.
In der Praxis
Eine typische MainActivity in einer Compose-first-App ist erstaunlich kurz. Sie macht im Kern drei Dinge: Sie aktiviert Edge-to-Edge, setzt das Compose-UI und delegiert alles Weitere an Composables und ViewModels.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AndroidCodenTheme {
AppRoot()
}
}
}
}
@Composable
fun AppRoot() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(onOpenDetails = { id ->
navController.navigate("details/$id")
}) }
composable("details/{id}") { backStackEntry ->
val id = backStackEntry.arguments?.getString("id").orEmpty()
DetailsScreen(id)
}
}
}
Beachte, wie wenig in der Activity steht. Es gibt keine Bildschirm-Logik, keine Datenladevorgänge, keine Validierung. All das passiert in den Screen-Composables und den dahinterliegenden ViewModels. Genau diese Aufteilung ist der Kern des Single-Activity-Modells.
Im AndroidManifest.xml registrierst du die Activity einmal sauber als Einstiegspunkt:
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.AndroidCoden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Eine typische Stolperfalle, in die fast jeder Anfänger einmal tappt, ist das Halten von UI-State direkt in Activity-Feldern. Du legst zum Beispiel var counter = 0 als Property in der Activity an, baust einen Button und freust dich. Dann drehst du das Gerät und der Zähler springt zurück auf null, weil die Activity neu erstellt wurde. Die Lösung ist, den State entweder mit rememberSaveable in Compose zu speichern oder, sobald er etwas komplexer wird, in ein ViewModel zu verschieben.
Eine zweite Falle ist das Starten langer Operationen in onCreate. Wenn du dort einen Netzwerkaufruf direkt im Main-Thread anstößt, blockierst du das UI und riskierst eine ANR-Meldung („Application Not Responding”). Lade Daten stattdessen aus einem ViewModel über Coroutines, idealerweise erst, wenn die UI sie wirklich braucht.
Eine klare Entscheidungsregel für deine Praxis: Wenn du dich fragst, ob neuer Code in die Activity oder in ein Composable/ViewModel gehört, prüfe, ob das System diesen Code unbedingt am Activity-Lebenszyklus aufhängen muss. Geht es um Fenster, Permissions, System-Intents oder Edge-to-Edge? Dann Activity. Geht es um Daten, UI-State oder Bildschirm-Verhalten? Dann ViewModel oder Composable.
Validierung deines Verständnisses
Du kannst dein Wissen sehr direkt überprüfen, indem du in jede Lebenszyklus-Methode einen Log.d-Aufruf einbaust und dann mit dem Gerät experimentierst: App öffnen, Home-Button drücken, zurückwechseln, Gerät drehen, Zurück-Taste nutzen. Beobachte im Logcat, in welcher Reihenfolge die Methoden aufgerufen werden. Ergänze danach ein ViewModel mit einer einfachen Zähler-Variable und vergleiche, wie sich der Zustand bei einer Drehung verhält, je nachdem, ob der Zähler im Composable, in rememberSaveable oder im ViewModel liegt.
Fazit
Eine Activity ist kein Auslaufmodell, sondern der stabile Rahmen, in dem deine Compose-UI lebt. Du verstehst sie am besten, wenn du sie als dünnen Plattform-Adapter betrachtest: Sie startet die App, hält das Fenster, reagiert auf Lebenszyklus-Ereignisse und übergibt alles Weitere an Composables und ViewModels. In einer Single-Activity-Architektur reicht meist eine einzige MainActivity, und das ist genau die Klarheit, die moderne Android-Apps so wartbar macht. Nimm dir jetzt zehn Minuten, öffne dein aktuelles Projekt, prüfe, welche Logik wirklich in der Activity liegt, und verschiebe alles, was nicht plattform-nah ist, in ein Composable oder ein ViewModel. Setze ergänzend Logs in die Lebenszyklus-Methoden und beobachte das Verhalten beim Drehen und App-Wechsel — danach hast du ein belastbares mentales Modell, auf dem du jeden weiteren Roadmap-Schritt sicher aufbauen kannst.