Performance Mindset
Performance beginnt mit Messung. Du optimierst Android-Apps gezielt nach Nutzerwirkung, Engpässen und Trade-offs.
Performance Mindset heißt: Du behandelst Performance nicht als Bauchgefühl, sondern als überprüfbare Eigenschaft deiner App. Du fragst zuerst, welches konkrete Nutzerproblem vorliegt, misst es mit passenden Werkzeugen und entscheidest dann, ob eine Optimierung den Aufwand und die Nebenwirkungen wert ist.
Was ist das?
Ein Performance Mindset ist eine Denkweise für technische Entscheidungen. Du optimierst nicht, weil Code „schneller aussehen“ soll, sondern weil Nutzerinnen und Nutzer eine App als träge, ruckelig, stromhungrig oder unzuverlässig erleben. Der zentrale Satz lautet: Miss den Effekt, finde den Engpass, entscheide den Trade-off.
Im Android-Kontext ist das besonders wichtig, weil Geräte, Android-Versionen, Displaygrößen, Akkustände und Netzwerkbedingungen stark variieren. Eine App kann auf deinem Entwicklungsgerät flüssig wirken und auf einem älteren Mittelklassegerät trotzdem beim Start hängen. Auch moderne Frameworks wie Jetpack Compose nehmen dir diese Verantwortung nicht ab. Compose kann sehr effizient sein, aber unnötige Recompositions, zu große Listen-Elemente oder teure Berechnungen im UI-Pfad können trotzdem sichtbar werden.
Als Lernender solltest du dir früh ein klares Modell aufbauen: Performance ist kein einzelner Wert. Startzeit, Bildrate, Speicherverbrauch, Akkunutzung, Netzwerkverhalten und Reaktionszeit sind unterschiedliche Ziele. Sie können sich gegenseitig beeinflussen. Eine aggressive Zwischenspeicherung kann Netzwerkzugriffe reduzieren, aber Speicher kosten. Eine komplexere Architektur kann Wiederholungen vermeiden, aber schwerer zu verstehen sein. Ein gutes Performance Mindset erkennt diese Abwägungen und vermeidet reflexartige Optimierungen.
Wie funktioniert es?
Der Ablauf beginnt mit einer Beobachtung. Zum Beispiel: Der erste Bildschirm erscheint langsam, eine LazyColumn ruckelt, ein Button reagiert verzögert oder ein Sync-Vorgang leert den Akku. Danach formulierst du eine messbare Frage. Nicht: „Ist die App langsam?“, sondern: „Wie lange dauert es vom App-Start bis zum ersten nutzbaren Inhalt auf einem realistischen Gerät?“ oder „Warum wird beim Scrollen regelmäßig der Frame-Zeitbereich überschritten?“
Dann suchst du den Engpass. Ein Engpass ist die Stelle, die das Gesamterlebnis begrenzt. Das kann CPU-Arbeit im Main Thread sein, ein blockierender Datenbankzugriff, zu viel JSON-Verarbeitung, ein schlecht gewählter Netzwerkzeitpunkt, unnötige Objekt-Erzeugung oder ein Compose-State, der zu große Teile des UI neu berechnen lässt. Wichtig ist: Du errätst den Engpass nicht, du grenzt ihn ein.
In der täglichen Android-Entwicklung taucht diese Denkweise an vielen Stellen auf. Bei Kotlin-Coroutines prüfst du, ob teure Arbeit wirklich außerhalb des Main Threads läuft. Bei Room achtest du darauf, ob Queries passend indiziert sind und ob du Datenströme sinnvoll beobachtest. In Compose prüfst du, ob State nah genug an der Stelle liegt, die ihn braucht, und ob Listen stabile Keys verwenden. In der Release-Praxis schaust du nicht nur auf lokale Tests, sondern auch auf reale Kennzahlen wie Startzeit, Abstürze, ANRs und Nutzerberichte.
Der wichtigste Mechanismus ist die Rückkopplung: Änderung, Messung, Vergleich. Wenn du vor einer Änderung eine Baseline hast, kannst du danach beurteilen, ob sich etwas verbessert hat. Ohne Baseline kann eine Optimierung nur gefühlt wirken. Gerade für Junior-Devs ist das ein häufiger Lernpunkt: Sauberer Code und schneller Code sind nicht dasselbe, aber sie stehen auch nicht automatisch im Gegensatz. Oft verbessert eine klare Datenfluss-Struktur sogar die Performance, weil weniger unnötige Arbeit passiert.
In der Praxis
Stell dir eine Compose-App vor, die eine Liste von Artikeln anzeigt. Beim Scrollen wirkt sie ruckelig. Eine voreilige Reaktion wäre, sofort die gesamte Liste umzubauen oder eigene Caches einzuführen. Mit Performance Mindset gehst du anders vor: Du reproduzierst das Problem, misst den UI-Pfad und suchst nach der teuersten Arbeit pro Listenelement.
Ein typischer Fehler ist teure Formatierung direkt im Composable. Wenn jedes sichtbare Element bei jeder Recomposition Datum, Text oder Status neu berechnet, kann das bei langen Listen auffallen. Besser ist es, diese Arbeit im ViewModel oder beim Mapping in ein UI-Modell vorzubereiten.
data class ArticleUiItem(
val id: Long,
val title: String,
val formattedDate: String,
val readingTimeLabel: String
)
class ArticleViewModel(
private val repository: ArticleRepository
) : ViewModel() {
val articles: StateFlow<List<ArticleUiItem>> =
repository.observeArticles()
.map { articles ->
articles.map { article ->
ArticleUiItem(
id = article.id,
title = article.title,
formattedDate = formatDate(article.publishedAt),
readingTimeLabel = "${article.readingMinutes} Min. Lesezeit"
)
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList()
)
}
@Composable
fun ArticleList(items: List<ArticleUiItem>) {
LazyColumn {
items(
items = items,
key = { it.id }
) { item ->
Text(text = item.title)
Text(text = item.formattedDate)
Text(text = item.readingTimeLabel)
}
}
}
Dieses Beispiel ist absichtlich klein. Der Punkt ist nicht, dass jede Formatierung immer ausgelagert werden muss. Der Punkt ist die Entscheidungsregel: Arbeit, die häufig im UI-Pfad wiederholt wird und messbar stört, gehört geprüft. Wenn sie teuer ist, verschiebst du sie an eine Stelle, an der sie seltener läuft oder besser kontrollierbar ist.
Eine zweite Regel: Optimiere nicht gegen ein theoretisches Ideal, sondern gegen einen beobachteten Engpass. Wenn die Liste flüssig scrollt, ist ein zusätzlicher Cache möglicherweise nur neue Komplexität. Wenn Messungen zeigen, dass die Datenbankabfrage dominiert, bringt dir ein Umbau der Composables wenig. Wenn das Netzwerk langsam ist, hilft vielleicht ein besserer Ladezustand oder inkrementelles Anzeigen mehr als Mikro-Optimierung im Code.
Eine typische Stolperfalle ist die Verwechslung von lokaler Geschwindigkeit und Nutzerwirkung. Ein Algorithmus kann in einem Benchmark schneller sein, aber im echten Ablauf kaum Bedeutung haben, weil er selten läuft. Umgekehrt kann eine kleine Berechnung problematisch werden, wenn sie pro Frame oder pro Listenelement passiert. Frage deshalb immer: Wie oft läuft dieser Code, auf welchem Thread läuft er, und merkt der Nutzer den Unterschied?
Nutze Code-Reviews für diese Fragen. Ein Review sollte nicht nur prüfen, ob die Lösung funktioniert, sondern auch, ob sie unnötige Arbeit erzeugt. Läuft I/O auf dem Main Thread? Werden große Objekte in Composables erzeugt? Wird State so breit gehalten, dass ganze Bildschirme neu berechnet werden? Gibt es eine Messung oder wenigstens eine begründete Annahme, warum diese Optimierung nötig ist?
Fazit
Performance Mindset macht dich zu einem zuverlässigeren Android-Entwickler, weil du nicht auf Vermutungen optimierst. Übe das konkret: Nimm einen langsamen Bildschirm, formuliere eine messbare Frage, erstelle eine Baseline, ändere nur eine relevante Sache und vergleiche danach. Prüfe deine Erkenntnisse mit Profiling, Debugger, Tests oder Code-Review. So lernst du, Engpässe zu finden, Abwägungen bewusst zu treffen und Performance als Teil professioneller App-Qualität zu behandeln.