Einige Gerätekonfigurationen können sich ändern, während die App ausgeführt wird. Dazu gehören unter anderem:
- Anzeigegröße der App
- Bildschirmdichte (Anzeigenskalierung)
- Bildschirmausrichtung
- Schriftgröße und -stärke
- Sprache
- Dunkles Design im Vergleich zum hellen Design
- Verfügbarkeit der Tastatur
Die meisten dieser Konfigurationsänderungen werden durch Nutzerinteraktionen verursacht. Wenn du das Gerät beispielsweise drehst oder faltest, ändert sich die für deine App verfügbare Bildschirmfläche. Wenn du eine Verbindung zu externen Displays herstellst oder eine App zwischen Displays mit unterschiedlichen Pixeldichten verschiebst, ändern sich die Pixeldichte und die Displaygröße. Ebenso werden durch das Ändern von Geräteeinstellungen wie der Displayskalierung, der Schriftgröße, der Sprache oder des bevorzugten Designs die entsprechenden Werte im Configuration-Objekt geändert.
Diese Parameter erfordern in der Regel so große Änderungen an der Benutzeroberfläche Ihrer Anwendung, dass die Android-Plattform einen speziellen Mechanismus für den Fall hat, dass sie sich ändern.
Dieser Mechanismus ist die Neuerstellung von Activity.
Aktivitätsrekonstruktion
Das System erstellt eine Activity neu, wenn eine Konfigurationsänderung auftritt. Dazu ruft das System onDestroy auf und löscht die vorhandene Activity-Instanz. Anschließend wird mit onCreate eine neue Instanz erstellt und diese neue Activity-Instanz wird mit der neuen, aktualisierten Konfiguration initialisiert. Das bedeutet auch, dass das System die Benutzeroberfläche mit der neuen Konfiguration neu erstellt.
In der Regel fungiert die Activity als Host für Compose-Funktionen. Wenn die Activity neu erstellt wird, erstellt Compose auch die Benutzeroberfläche mit den neuen Konfigurationswerten neu.
Das Neuerstellungsverhalten hilft Ihrer Anwendung, sich an neue Konfigurationen anzupassen, indem sie automatisch mit alternativen Ressourcen neu geladen wird, die der neuen Gerätekonfiguration entsprechen.
Beispiel für Freizeitaktivitäten
Sehen wir uns eine zusammensetzbare Funktion an, die einen statischen Titel mithilfe einer String-Ressource anzeigt:
// In the res/values/strings.xml file // <string name="compose">Jetpack Compose</string> // In your Compose code Text( text = stringResource(R.string.compose) )
Wenn die Activity erstellt wird, liest die Text-komponierbare Funktion die aktuelle Konfiguration (z. B. die Sprache) und löst die entsprechende String-Ressource auf.
Wenn sich die Sprache ändert, wird die Aktivität vom System neu erstellt. In diesem Fall erstellt Compose die UI neu. Da stringResource aus der aktuellen Konfiguration liest, wird der Titel automatisch auf den richtigen lokalisierten Wert aktualisiert.
Durch die Neuerstellung werden auch alle Zustände gelöscht, die als Felder im Activity gespeichert sind.
Verwenden Sie die empfohlenen Muster für die Statusverwaltung, um den UI-Status bei Konfigurationsänderungen beizubehalten. Verwenden Sie ViewModel für Daten und Geschäftslogik und rememberSaveable für den Status auf UI-Ebene. Mit diesen Mechanismen bleibt der Status bei der Neuerstellung von Activity erhalten, während die Benutzeroberfläche aktualisiert wird, um die neue Konfiguration widerzuspiegeln.
Weitere Informationen zum Speichern des Status in Compose finden Sie unter UI-Status in Compose speichern.
Erwartungen der Nutzer
Nutzer einer App erwarten, dass der Status beibehalten wird. Wenn ein Nutzer ein Formular ausfüllt und im Mehrfenstermodus eine andere App öffnet, um Informationen nachzuschlagen, ist es für ihn frustrierend, wenn er zu einem leeren Formular oder zu einer ganz anderen Stelle in der App zurückkehrt. Als Entwickler müssen Sie eine konsistente Nutzererfahrung bieten, auch wenn Konfigurationsänderungen vorgenommen und Aktivitäten neu erstellt werden.
Wenn Sie prüfen möchten, ob der Status in Ihrer Anwendung beibehalten wird, können Sie Aktionen ausführen, die Konfigurationsänderungen verursachen, während die App im Vordergrund und im Hintergrund ausgeführt wird. Diese Aktivitäten umfassen:
- Drehen des Geräts
- Mehrfenstermodus wird gestartet
- Größe der Anwendung im Mehrfenstermodus oder in einem Freiform-Fenster ändern
- Zusammenklappen eines faltbaren Geräts mit mehreren Displays
- Ändern der Anzeigegröße oder der Anzeigeskalierung in den Systemeinstellungen
- Verschieben der App zwischen Displays mit unterschiedlichen Pixeldichten (z. B. verbundene externe Monitore oder die Displays eines faltbaren Geräts)
- Ändern des Systemdesigns, z. B. dunkles Design im Vergleich zum hellen Design
- Schriftgröße ändern
- System- oder App-Sprache ändern
- Verbinden oder Trennen einer Hardwaretastatur
- Dock verbinden oder trennen
Es gibt mehrere Ansätze, um den relevanten Status bei der Neuerstellung von Activity beizubehalten. Welche Sie verwenden, hängt von der Art des Zustands ab, den Sie beibehalten möchten:
- Lokale Persistenz, um die Prozessbeendigung bei komplexen oder großen Daten zu verarbeiten.
Nichtflüchtiger lokaler Speicher umfasst Datenbanken oder
DataStore. - Beibehaltene Objekte wie
ViewModel-Instanzen, um den UI-bezogenen Status im Arbeitsspeicher zu verarbeiten, während der Nutzer die App aktiv verwendet. rememberSaveable, um den vorübergehenden UI-Zustand bei Konfigurationsänderungen und vom System initiierten Prozessbeendigungen beizubehalten. Dies ist für Zustände geeignet, die von Nutzereingaben, Scrollposition oder Navigation abhängen, aber nicht in einViewModelgehören.
Ausführliche Informationen zu den APIs für die einzelnen Optionen und dazu, wann sie jeweils verwendet werden sollten, findest du unter UI-Zustände speichern.
Neuerstellung von Aktivitäten einschränken
Sie können die automatische Neuerstellung von Aktivitäten für bestimmte Konfigurationsänderungen verhindern. In modernen Apps, die nur Compose verwenden, wird die Benutzeroberfläche so oder so neu zusammengesetzt. Es wird jedoch empfohlen, die Konfigurationsänderung direkt zu verarbeiten.
Standardmäßig wird das System durch eine Konfigurationsänderung gezwungen, die Aktivität zu löschen und neu zu erstellen, einschließlich der Benutzeroberfläche und aller von der Aktivität abgeleiteten Objekte. Wenn Sie deklarieren, dass Ihre Aktivität die Konfigurationsänderung selbst verarbeitet, verhindert das System dies. Stattdessen wird nur das Configuration-Objekt aktualisiert und Compose setzt die Benutzeroberfläche mit den neuen Werten neu zusammen.
Die direkte Verarbeitung von Konfigurationsänderungen in Compose bietet mehrere Vorteile:
- Verbesserte Leistung: Die Neuzusammensetzung der Benutzeroberfläche ist weniger aufwendig als ein vollständiger Zyklus zur Neuerstellung von Aktivitäten, insbesondere bei geringfügigen Änderungen.
- Flüssige Animationen: Wenn Sie einen Neustart der Aktivität vermeiden, können Sie kontinuierliche Animationen über Konfigurationsänderungen hinweg ausführen, z. B. flüssige Layoutübergänge beim Drehen des Geräts.
- Status beibehalten:Wenn die Aktivitätsinstanz beibehalten wird, sinkt das Risiko, dass vorübergehende UI-Status während eines Ereignisses wie der Bildschirmdrehung verloren gehen. Beachte, dass du die Zustandserhaltung für die vom System initiierte Prozessbeendigung weiterhin selbst verwalten musst.
Wenn Sie die Neuerstellung von Aktivitäten für bestimmte Konfigurationsänderungen deaktivieren möchten, fügen Sie den Konfigurationstyp in der Datei AndroidManifest.xml im Eintrag <activity> zu android:configChanges hinzu. Mögliche Werte finden Sie in der Dokumentation zum Attribut android:configChanges.
Mit dem folgenden Manifestcode wird die Neuerstellung von Activity für MyActivity deaktiviert, wenn sich die Bildschirmausrichtung und die Verfügbarkeit der Tastatur ändern:
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
Android 17
Ab Android 17 (API-Level 37) werden Aktivitäten bei mehreren Konfigurationsänderungen, die normalerweise keine vollständige Neuerstellung der Benutzeroberfläche erfordern, nicht mehr standardmäßig neu gestartet.
Stattdessen bleiben Aktivitäten aktiv und erhalten Updates über den Callback onConfigurationChanged().
Zu den spezifischen Konfigurationsänderungen gehören:
CONFIG_KEYBOARDCONFIG_KEYBOARD_HIDDENCONFIG_NAVIGATIONCONFIG_TOUCHSCREENCONFIG_COLOR_MODECONFIG_UI_MODE(nur wenn der UI-Modus zuUI_MODE_TYPE_DESKoder vonUI_MODE_TYPE_DESKzu einem anderen Typ wechselt)
Wenn Ihre Anwendung einen vollständigen Neustart erfordert, um Ressourcen für diese Änderungen neu zu laden, müssen Sie das alte Verhalten jetzt explizit mit dem Attribut android:recreateOnConfigChanges in der Manifestdatei aktivieren.
Mit dem Attribut können Sie angeben, welche Konfigurationsänderungen einen vollständigen Zyklus aus Aktivitätsstopp, Zerstörung und Neuerstellung auslösen sollen, z. B.:
<activity
android:name=".MyActivity"
android:recreateOnConfigChanges="keyboard|keyboardHidden|navigation|colorMode|touchscreen|...">
...
</activity>
Auf Konfigurationsänderungen reagieren
Mit Jetpack Compose kann Ihre App einfacher auf Konfigurationsänderungen reagieren.
Wenn Sie jedoch die Neuerstellung von Activity für alle Konfigurationsänderungen deaktivieren, bei denen dies möglich ist, muss Ihre App Konfigurationsänderungen trotzdem korrekt verarbeiten.
Das Configuration-Objekt ist in der Compose-UI-Hierarchie mit dem CompositionLocal LocalConfiguration verfügbar. Wenn sich der Wert ändert, werden zusammensetzbare Funktionen, die aus LocalConfiguration.current lesen, neu zusammengesetzt. Informationen zur Funktionsweise von CompositionLocals finden Sie unter Lokale Daten mit CompositionLocal.
Beispiel
Im folgenden Beispiel zeigt eine zusammensetzbare Funktion ein Datum in einem bestimmten Format an.
Die komponierbare Funktion reagiert auf Änderungen der Systemkonfiguration für die Sprache, indem sie ConfigurationCompat.getLocales mit LocalConfiguration.current aufruft.
@Composable
fun DateText(year: Int, dayOfYear: Int) {
val dateTimeFormatter = DateTimeFormatter.ofPattern(
"MMM dd",
ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
)
Text(
dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
)
}
Damit die Activity bei einer Änderung der Sprache nicht neu erstellt wird, muss die Activity, die den Compose-Code hostet, von Änderungen an der Sprachkonfiguration ausgeschlossen werden. Dazu setzen Sie android:configChanges auf locale|layoutDirection.
Konfigurationsänderungen: Wichtige Konzepte und Best Practices
Diese wichtigen Konzepte sollten Sie kennen, wenn Sie an Konfigurationsänderungen arbeiten:
- Konfigurationen:Gerätekonfigurationen legen fest, wie die Benutzeroberfläche dem Nutzer angezeigt wird, z. B. die Anzeigegröße der App, die Bildschirmdichte, das Gebietsschema oder das Systemdesign.
In Compose können Sie mit
LocalConfigurationauf Konfigurationswerte zugreifen. - Konfigurationsänderungen:Konfigurationen ändern sich durch Nutzerinteraktion. Beispielsweise kann der Nutzer die Geräteeinstellungen oder die physische Interaktion mit dem Gerät ändern. Es gibt keine Möglichkeit, Konfigurationsänderungen zu verhindern.
Activity-Neuerstellung: Konfigurationsänderungen führen standardmäßig zur Neuerstellung vonActivity. Dies ist ein integrierter Mechanismus, um den Anwendungsstatus für die neue Konfiguration neu zu initialisieren.Activity-Zerstörung: Durch die Neuerstellung vonActivitywird die alteActivity-Instanz zerstört und eine neue erstellt. Die alte Instanz ist jetzt veraltet. Vermeiden Sie es, Verweise auf Objekte mit Lebenszyklusbereich über den vorgesehenen Bereich hinaus beizubehalten.- Status: Der Status in der alten
Activity-Instanz ist in der neuenActivity-Instanz nicht vorhanden, da es sich um zwei verschiedene Objektinstanzen handelt. Anstatt den Status an die Aktivität zu binden, sollten Sie die empfohlenen APIs verwenden, um den Status der App und des Nutzers beizubehalten, wie unter UI-Status speichern beschrieben. - Deaktivieren:Wenn Sie die Neuerstellung von Aktivitäten für eine Art von Konfigurationsänderung deaktivieren, muss Ihre App ordnungsgemäß auf die neue Konfiguration reagieren.
Beachten Sie die folgenden Best Practices, um eine gute Nutzererfahrung zu bieten:
- Auf häufige Konfigurationsänderungen vorbereitet sein:Gehe nicht davon aus, dass Konfigurationsänderungen selten oder nie vorkommen, unabhängig von API-Level, Formfaktor oder UI-Toolkit. Wenn ein Nutzer eine Konfigurationsänderung vornimmt, erwartet er, dass Apps aktualisiert werden und mit der neuen Konfiguration weiterhin korrekt funktionieren.
- Status beibehalten: Der Status des Nutzers darf nicht verloren gehen, wenn
Activityneu erstellt wird. Behalten Sie den Status wie unter UI-Status speichern beschrieben bei, indem Sie APIs wieViewModelundrememberSaveableverwenden. - Vermeiden Sie die Deaktivierung als schnelle Lösung: Deaktivieren Sie die Neuerstellung von
Activitynicht, um einen Statusverlust zu vermeiden. Wenn Sie die Neuerstellung von Aktivitäten deaktivieren, müssen Sie die Änderung selbst verarbeiten. Der Status kann jedoch aufgrund der Neuerstellung vonActivitydurch andere Konfigurationsänderungen, Prozessbeendigung oder Schließen der App verloren gehen. Es ist nicht möglich, die Neuerstellung vonActivityvollständig zu deaktivieren. Behalten Sie den Status wie unter UI-Status speichern beschrieben bei. - Konfigurationsänderungen nicht vermeiden: Schränke die Ausrichtung, das Seitenverhältnis oder die Größenänderung nicht ein, um Konfigurationsänderungen und die Neuerstellung von
Activityzu vermeiden. Das wirkt sich negativ auf Nutzer aus, die Ihre App auf ihre bevorzugte Weise verwenden möchten.
Größenbasierte Konfigurationsänderungen verarbeiten
Größenbasierte Konfigurationsänderungen können jederzeit auftreten und sind wahrscheinlicher, wenn Ihre App auf einem Gerät mit großem Display ausgeführt wird, auf dem Nutzer den Mehrfenstermodus aktivieren können. Sie erwarten, dass Ihre App in dieser Umgebung gut funktioniert.
Es gibt zwei allgemeine Arten von Größenänderungen: signifikante und unbedeutende. Eine signifikante Größenänderung ist eine Änderung, bei der aufgrund eines Unterschieds in der Bildschirmgröße, z. B. Breite, Höhe oder kleinste Breite, ein anderer Satz alternativer Ressourcen für die neue Konfiguration gilt. Dazu gehören die von der App selbst definierten Ressourcen und die Ressourcen aus den Bibliotheken der App.
Neuerstellung von Aktivitäten bei größenbasierten Konfigurationsänderungen einschränken
Wenn Sie die Neuerstellung von Activity für größenbasierte Konfigurationsänderungen deaktivieren, wird die Activity nicht neu erstellt. Stattdessen wird ein Aufruf an Activity.onConfigurationChanged gesendet. Alle Composables, die LocalConfiguration.current lesen, werden automatisch neu zusammengesetzt, um die neue Größe widerzuspiegeln.
Die Neuerstellung von Activity ist für größenbasierte Konfigurationsänderungen deaktiviert, wenn Sie android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" in Ihrer Manifestdatei haben.
Zusätzliche Ressourcen
Weitere Informationen zum Umgang mit Konfigurationsänderungen finden Sie in den folgenden zusätzlichen Ressourcen: