Android-Interviews drehen sich um Kotlin-Idiome, Coroutines und den Lifecycle der Plattform – die meisten Senior-Fragen wollen im Kern nur wissen, ob dir klar ist, dass dein Prozess jederzeit beendet werden kann. Es folgen die am häufigsten gestellten Fragen, jede mit einer Musterantwort.
Zu jeder Frage gibt es eine Musterantwort, mit der du deine eigene vergleichen kannst.
1
Wie funktioniert Null Safety in Kotlin, und wann ist ein Platform Type gefährlich?
Antwort
Kotlin teilt jeden Typ in nullable (String?) und non-nullable (String) auf, und der Compiler verweigert das Dereferenzieren eines nullable Werts ohne Prüfung, wodurch NullPointerException größtenteils verschwindet. Platform Types entstehen an der Grenze zu Java: Kotlin weiß nicht, ob eine Java-Methode null zurückgeben kann, und vertraut dir. Genau daher kommen NPEs immer noch – annotiere Java-APIs oder behandle deren Ergebnisse an der Aufrufstelle als nullable.
2
Was bringen dir data classes und sealed classes?
Antwort
Eine data class generiert equals, hashCode, toString, copy und Destrukturierung aus dem primären Konstruktor, was sie zum richtigen Werkzeug für Werte macht, die du vergleichst und kopierst – API-Modelle, UI-State. Eine sealed class beschränkt ihre Subklassen auf eine bekannte Menge, sodass ein when darüber vollständig ist und der Compiler jeden vergessenen Zweig meldet. Zusammen modellieren sie UI-State sauber: ein sealed interface für Loading, Content, Error, mit data classes, die die Payload tragen.
3
Was ist Structured Concurrency bei Coroutines, und wofür ist ein Scope da?
Antwort
Structured Concurrency bedeutet, dass jede Coroutine zu einem Scope und einem Parent-Job gehört, sodass das Abbrechen des Parents alle Kinder abbricht und der Parent nicht abschließt, bevor sie das tun. Genau das verhindert die entkoppelte Hintergrundarbeit, die bei rohen Threads entsteht. Auf Android wird viewModelScope abgebrochen, wenn das ViewModel geleert wird, und lifecycleScope, wenn der Lifecycle endet – Arbeit stoppt also, sobald ihr Ergebnis nicht mehr verwendet werden kann.
4
Erkläre die Dispatcher und wofür du welchen einsetzt.
Antwort
Dispatchers.Main läuft auf dem UI-Thread, dort fasst du Views an. Dispatchers.IO ist ein großer, elastischer Pool für blockierende Arbeit – Disk, Netzwerk, Datenbank –, weil diese Threads die meiste Zeit warten. Dispatchers.Default ist an die Anzahl der CPU-Kerne angepasst und für echte Berechnung wie Parsen oder Sortieren gedacht. Ein blockierender Aufruf auf Default hungert den Pool aus – das ist der häufigste Dispatcher-Fehler.
5
Was ist der Unterschied zwischen Flow, StateFlow und LiveData?
Antwort
Flow ist ein kalter, asynchroner Stream: Er beginnt erst zu produzieren, wenn er gesammelt wird, und jeder Collector bekommt seine eigene Ausführung. StateFlow ist heiß und hält immer genau einen aktuellen Wert, was ihn zur natürlichen Wahl für UI-State macht – neue Collector erhalten sofort den aktuellsten Zustand. LiveData ist der ältere lifecycle-aware Halter; StateFlow zusammen mit repeatOnLifecycle deckt denselben Bedarf mit dem restlichen Coroutines-Werkzeugkasten ab, weshalb neuer Code in der Regel StateFlow bevorzugt.
6
Warum erzeugt eine Konfigurationsänderung die Activity neu, und wie überstehst du das?
Antwort
Rotation, Dark Mode, Sprach- und Fenstergrößenänderungen zerstören und erzeugen die Activity neu, damit sie Ressourcen für die neue Konfiguration laden kann. Zustand, der das überstehen muss, gehört in ein ViewModel, das die Neuerstellung übersteht. Zustand, der auch einen Prozesstod überstehen muss, gehört in SavedStateHandle, weil das System deinen Prozess im Hintergrund beenden und den Task später wiederherstellen kann – dies mit "Don't keep activities" zu testen, unterscheidet eine robuste App von einer, die Nutzereingaben verliert.
7
Was löst Recomposition in Jetpack Compose aus, und wodurch wird sie langsam?
Antwort
Compose führt ein Composable erneut aus, wenn sich ein gelesener State ändert, und überspringt Composables, deren Parameter gleich und stabil sind. Langsamkeit entsteht durch instabile Parameter – eine einfache List oder eine Lambda, die einen sich ändernden Wert einfängt –, die das Überspringen verhindern und große Teilbäume neu ausführen. Die Fixes sind, State zum niedrigsten gemeinsamen Owner zu heben, immutable Collections oder @Immutable-Annotationen zu nutzen und Lesezugriffe mit Lambdas zu verzögern, sodass nur die Layout- oder Draw-Phase erneut läuft.
8
Warum Dependency Injection mit Hilt statt Objekte direkt zu konstruieren?
Antwort
DI nimmt einer Klasse die Notwendigkeit, zu wissen, wie sie ihre Abhängigkeiten baut, was sie testbar macht und die Verdrahtung an einem Ort bündelt statt über verstreute Singletons. Hilt generiert den Dagger-Graphen und bindet die Lebensdauer von Komponenten an Android-Lebenszyklen – ein @Singleton lebt mit der Application, ein @ViewModelScoped-Binding mit dem ViewModel. Der praktische Gewinn ist, in Tests ein echtes Repository durch ein Fake zu ersetzen, ohne Produktionscode anzufassen.
9
Wie strukturierst du einen Screen im Sinne von Clean Architecture?
Antwort
Der UI-Layer enthält Compose oder Views plus ein ViewModel, das immutable State exponiert und Events entgegennimmt. Der Domain-Layer enthält Use Cases und reine Business-Regeln ohne Android-Imports, was ihn mit reinem JUnit testbar macht. Der Data-Layer enthält Repositories, die zwischen Room und Retrofit entscheiden und DTOs auf Domain-Modelle mappen. Die entscheidende Regel ist die Abhängigkeitsrichtung: Domain weiß nichts von Data oder UI.
10
Wodurch entsteht ein ANR, und wie findest du einen nach dem Release?
Antwort
Ein ANR feuert, wenn der Main Thread etwa fünf Sekunden lang bei Input blockiert ist, bei Broadcasts und Services gelten kürzere Grenzen. Typische Ursachen sind Datenbank- oder Netzwerkaufrufe auf dem Main Thread, ein riesiges synchrones JSON-Parsing oder Lock-Contention mit einem Hintergrund-Thread. Nach dem Release zeigen die ANR-Reports der Play Console zusammen mit dem erfassten Main-Thread-Stack auf den blockierenden Frame; StrictMode in Debug-Builds fängt das meiste davon lange vor dem Release ab.
11
Wie vermeidest du Memory Leaks in Android?
Antwort
Die wiederkehrende Ursache ist etwas Langlebiges, das eine Activity oder View hält – eine statische Referenz, ein nie deregistrierter Listener, eine innere Klasse mit impliziter Referenz auf ihre äußere, oder eine Coroutine auf GlobalScope. Die Gegenmittel sind, Arbeit an einen lifecycle-aware Scope zu binden, Binding-Referenzen in onDestroyView bei Fragments zu leeren und den Application Context zu verwenden, wo kein Activity Context nötig ist. LeakCanary in Debug-Builds fängt den Rest ab, indem es den haltenden Pfad meldet.
12
Was sind die Scope Functions, und wann liest sich welche am besten?
Antwort
let übernimmt den Empfänger als Argument und gibt das Lambda-Ergebnis zurück, passt also für Null-Prüfung und Transformation. run macht dasselbe, aber mit this, nützlich für einen Block von Aufrufen, der einen Wert zurückgibt. apply gibt den Empfänger zurück und dient der Konfiguration eines Objekts. also gibt ebenfalls den Empfänger zurück, übergibt ihn aber als it, weshalb es sich für Seiteneffekte wie Logging eignet. with ist keine Extension und gruppiert einfach Aufrufe auf einem Objekt. Die Wahl nach Rückgabewert und Empfängerform hält sie lesbar statt clever.
🦎
Antworten lesen reicht nicht
Im echten Interview sprichst du unter Druck. Cam stellt genau diese Fragen, bewertet jede Antwort und zeigt dir genau, was du verbessern musst.
Android (Kotlin)-Interview üben →Kostenlos · 3 Interviews im Monat