Configuration Changes in Android: UI nach Rotation und Sprachwechsel sauber wiederherstellen
Configuration Changes sorgen dafür, dass Android deine UI bei Rotation oder Sprachwechsel neu aufbaut. Du lernst, wie du Zustand zuverlässig hältst.
Du drehst dein Testgerät, und plötzlich ist die Eingabe im Login-Feld weg. Genau das passiert, wenn du dich nicht um Configuration Changes kümmerst: Android baut die UI in solchen Momenten neu auf, und alles, was nur im Speicher der Activity lebt, geht verloren. In diesem Artikel siehst du, was dahintersteckt, warum es ein bewusst gewähltes Design ist und wie du Rotation, Sprachwechsel und Größenänderungen so abfederst, dass sich deine App stabil anfühlt — auf einem Pixel ebenso wie auf einem Foldable oder einem deutsch-sprachigen Gerät.
Was ist das?
Configuration Changes sind Änderungen an der Geräte-Konfiguration, die zur Laufzeit auftreten und das Layout, die Ressourcen oder das Verhalten deiner App beeinflussen. Die häufigsten Auslöser sind Bildschirm-Rotation, ein Wechsel der Systemsprache (Locale), Dark/Light-Mode, geänderte Schriftgrößen, eine ausgeklappte Foldable-Anzeige oder das Anschließen eines externen Displays. Android erfasst solche Wechsel über die Systemklasse Configuration und reagiert standardmäßig damit, dass die aktive Activity zerstört (onDestroy) und unmittelbar neu erstellt (onCreate) wird. Genau dort verlierst du jeden Zustand, den du nicht aktiv gerettet hast.
Das klingt zunächst aggressiv, hat aber einen klaren Grund: Nur durch das vollständige Neuladen der Ressourcen bekommst du automatisch das richtige Layout für die neue Bildschirmgröße, die übersetzten Strings für die neue Sprache und die passenden Drawables für die neue Pixeldichte. Du kannst dir das wie einen sauberen Re-Render aus dem Ressourcen-System vorstellen — und genau diese Garantie nehmen dir Architecture Components und Compose ab, sobald du sie richtig einsetzt. Mit anderen Worten: Configuration Changes sind kein Bug, sondern eine Spezifikation, an der du dein Architektur-Modell ausrichten solltest.
Wie funktioniert es?
Hinter der Bühne läuft folgender Ablauf: Das System bemerkt eine Änderung an android.content.res.Configuration, ruft onSaveInstanceState(Bundle) auf, beendet die Activity und startet sie mit derselben Bundle-Referenz neu in onCreate(Bundle?). Über das Bundle bekommst du primitive Werte, Strings und Parcelable-Objekte zurück — niemals offene Sockets, laufende Coroutinen oder UI-Hierarchien.
Damit du nicht bei jeder Drehung dein gesamtes Modell neu lädst, gibt es zwei zentrale Bausteine: das ViewModel und den SavedStateHandle. Ein ViewModel ist an einen ViewModelStoreOwner gebunden, der Konfigurationswechsel überlebt — die Activity wird zwar neu erstellt, aber dein ViewModel bleibt dieselbe Instanz mit denselben StateFlows und laufenden Coroutinen. Für Werte, die zusätzlich einen Prozess-Tod überleben sollen (z. B. Suchanfragen oder Eingabefelder), legst du sie in SavedStateHandle ab; das ist intern an onSaveInstanceState gebunden.
Compose und das Ressourcen-System
In Compose tritt rememberSaveable an die Stelle eines einfachen remember-Aufrufs, sobald der Wert einen Configuration Change überleben soll. Parallel arbeitet das Ressourcen-System: Anhand von Qualifiern wie values-de/, values-night/, layout-sw600dp/ oder drawable-xxhdpi/ wählt Android nach jedem Wechsel automatisch passende Inhalte aus. Compose erkennt die geänderte Configuration über LocalConfiguration und löst eine Recomposition aus, sodass stringResource, painterResource und Größen-bedingte Branches sofort die neue Variante laden.
Manuelle Behandlung — die Ausnahme
Du kannst Configuration Changes auch selbst übernehmen, indem du im Manifest android:configChanges="orientation|screenSize|locale|uiMode" setzt und onConfigurationChanged() überschreibst. Damit verhinderst du die Activity-Neuerstellung. Das solltest du aber nur in Spezialfällen tun — etwa für laufende Videoaufnahmen oder eingebettete WebViews mit teurem Zustand —, weil du dabei den automatischen Ressourcen-Wechsel bewusst aushebelst und ihn dann selbst wieder anstoßen musst.
In der Praxis
Stell dir einen Login-Screen vor: ein Eingabefeld für die E-Mail und ein Button. Ohne Vorbereitung verschwindet die getippte Adresse, sobald der Nutzer das Gerät dreht. Mit Compose und einem ViewModel wird daraus stabiler Zustand:
class LoginViewModel(
private val state: SavedStateHandle
) : ViewModel() {
val email: StateFlow<String> = state.getStateFlow("email", "")
fun updateEmail(value: String) {
state["email"] = value
}
}
@Composable
fun LoginScreen(viewModel: LoginViewModel = viewModel()) {
val email by viewModel.email.collectAsStateWithLifecycle()
Column(Modifier.padding(16.dp)) {
OutlinedTextField(
value = email,
onValueChange = viewModel::updateEmail,
label = { Text(stringResource(R.string.label_email)) }
)
Button(onClick = { /* ... */ }) {
Text(stringResource(R.string.action_login))
}
}
}
Hier greifen mehrere Mechanismen ineinander. Der SavedStateHandle rettet die Eingabe über Rotation und Prozess-Tod. stringResource lädt nach einem Locale-Wechsel automatisch den deutschen oder englischen Text aus dem passenden values-*/strings.xml. Wenn du zusätzlich ein layout-sw600dp/-Pendant für Tablets hinterlegst — oder in Compose mit WindowSizeClass arbeitest — bekommt der Nutzer auf einem ausgeklappten Foldable sofort das breitere Layout, ohne dass du im Code Sondernfälle bauen musst.
Typische Stolperfallen
- Hardcodierte Strings direkt im Composable (
Text("Login")) umgehen das Ressourcen-System und ignorieren jeden Locale-Wechsel. Lege Texte konsequent inres/values/strings.xmlab und referenziere sie überstringResource(...). remember { mutableStateOf("") }für Eingabefelder verliert seinen Wert bei der Rotation. Greife zurememberSaveableoder spiegle den Zustand in einViewModel.- Aufwendige Datenbank- oder Netzwerk-Aufrufe direkt in
onCreatemachen jede Drehung träge. Verlagere sie in dasViewModelmitviewModelScope-Coroutinen — die starten nur einmal proViewModel-Lebenszeit, nicht bei jeder Activity-Neuerstellung. - Bilder oder Strings, die nur in
values/liegen, sehen auf einem deutschen Gerät englisch aus. Pflegevalues-de/von Beginn an, auch wenn du die Übersetzungen erst später ergänzt.
Fazit
Configuration Changes sind kein Rand-Thema, sondern ein Kern-Mechanismus von Android. Wenn du verstehst, warum die Plattform deine Activity neu aufbaut, fällt es leichter, sauberen Zustand zu modellieren: ViewModel für In-Memory-Daten, SavedStateHandle und rememberSaveable für Werte, die jeden Sturm überleben sollen, Ressourcen-Qualifier für alles, was sich mit Sprache, Theme oder Bildschirm ändert. Prüfe das selbst — dreh dein Test-Gerät, schalte die Sprache auf Deutsch und zurück auf Englisch, aktiviere im Entwickler-Menü „Don’t keep activities“, und beobachte, was deine App noch weiß. Schreibe einen Compose-UI-Test, der diese Szenarien automatisiert abdeckt, oder mach es zur Regel im Code-Review, jedes neue Composable mit Eingabefeldern auf rememberSaveable zu prüfen. Das ist der schnellste Weg, Configuration-Bugs zu fangen, bevor ein Nutzer sie meldet.