Einige Gerätekonfigurationen können sich ändern, während die App ausgeführt wird. Dazu gehören unter anderem:
- Anzeigegröße der App
- Bildschirmdichte (Anzeigeskalierung)
- Bildschirmausrichtung
- Schriftgröße und -stärke
- Sprache
- Dunkles oder helles Design
- Verfügbarkeit der Tastatur
Die meisten dieser Konfigurationsänderungen werden durch eine Nutzerinteraktion ausgelöst. Wenn Sie beispielsweise das Gerät drehen oder zusammenklappen, ändert sich der für Ihre App verfügbare Bildschirmplatz. Wenn Sie eine Verbindung zu externen Displays herstellen oder eine App zwischen Displays mit unterschiedlicher Pixeldichte verschieben, ändert sich die Bildschirmdichte und die Anzeigegröße. Wenn Sie Geräteeinstellungen wie Anzeigeskalierung, Schriftgröße,
Sprache oder bevorzugtes Design ändern, werden auch 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 speziell entwickelten Mechanismus für den Fall hat, dass sie sich ändern.
Dieser Mechanismus ist die Neuerstellung von Activity.
Neuerstellung von `Activity`
Das System erstellt eine Activity neu, wenn eine Konfigurationsänderung auftritt. Dazu ruft das System onDestroy auf und zerstört die vorhandene Activity
Instanz. Anschließend wird mit onCreate eine neue Instanz erstellt. 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 Composables. Wenn die Activity neu erstellt wird, erstellt Compose auch die Benutzeroberfläche mit den neuen Konfigurationswerten neu.
Durch das Neuerstellungsverhalten kann sich Ihre Anwendung an neue Konfigurationen anpassen, indem sie automatisch mit alternativen Ressourcen neu geladen wird, die der neuen Gerätekonfiguration entsprechen.
Beispiel für die Neuerstellung
Stellen Sie sich ein Composable vor, das einen statischen Titel mit 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 das Text-Composable die aktuelle Konfiguration (z. B. die Sprache) und löst die entsprechende String-Ressource auf.
Wenn sich die Sprache ändert, erstellt das System die Aktivität neu. In diesem Fall erstellt Compose die Benutzeroberfläche neu. Da stringResource aus der aktuellen Konfiguration liest, wird der Titel automatisch auf den richtigen lokalisierten Wert aktualisiert.
Bei der Neuerstellung wird auch der Status gelöscht, der als Felder in der Activity gespeichert ist.
Wenn Sie den UI-Status bei Konfigurationsänderungen beibehalten möchten, verwenden Sie die empfohlenen Muster für die Statusverwaltung. 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 schlecht für die Nutzererfahrung, wenn er zu einem leeren Formular oder an eine ganz andere Stelle in der App zurückkehrt. Als Entwickler müssen Sie bei Konfigurationsänderungen und der Neuerstellung von Aktivitäten eine konsistente Nutzererfahrung bieten.
Um zu prüfen, ob der Status in Ihrer Anwendung beibehalten wird, können Sie Aktionen ausführen, die Konfigurationsänderungen verursachen, sowohl wenn die App im Vordergrund als auch im Hintergrund ausgeführt wird. Diese Aktivitäten umfassen:
- Gerät drehen
- Mehrfenstermodus starten
- Größe der Anwendung im Mehrfenstermodus oder in einem Freiform-Fenster ändern
- Faltbares Gerät mit mehreren Displays zusammenklappen
- Anzeigegröße oder Anzeigeskalierung in den Systemeinstellungen ändern
- App zwischen Displays mit unterschiedlicher Bildschirmdichte verschieben (z. B. verbundene externe Monitore oder die Displays eines faltbaren Geräts)
- Systemdesign ändern, z. B. von dunkel zu hell
- Schriftgröße ändern
- System- oder App-Sprache ändern
- Hardwaretastatur anschließen oder trennen
- Dockingstation anschließen oder trennen
Es gibt mehrere Möglichkeiten, den relevanten Status bei der Neuerstellung von Activity beizubehalten. Welche Methode Sie verwenden, hängt vom Typ des Status ab, den Sie beibehalten möchten:
- Lokale Persistenz, um den Prozessabbruch bei komplexen oder großen Daten zu verarbeiten.
Permanenter 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 temporären UI-Status bei Konfigurationsänderungen und dem vom System initiierten Prozessabbruch beizubehalten. Dies ist für den Status geeignet, der von der Nutzereingabe, der Scrollposition oder der Navigation abhängt, aber nicht in eineViewModelgehört.
Informationen zu den APIs für die einzelnen Methoden und wann die Verwendung der jeweiligen Methode geeignet ist, finden Sie unter UI-Status 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 zwingt eine Konfigurationsänderung das System, die Activity einschließlich der Benutzeroberfläche und aller von der Activity abgeleiteten Objekte zu löschen und neu zu erstellen. 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 hat mehrere Vorteile:
- Verbesserte Leistung:Das Neuzusammensetzen der Benutzeroberfläche ist weniger aufwendig als ein vollständiger Neuerstellungszyklus für Aktivitäten, insbesondere bei kleineren Änderungen.
- Flüssige Animationen:Wenn Sie einen Neustart der Aktivität vermeiden, können Sie kontinuierliche Animationen bei Konfigurationsänderungen ausführen, z. B. reibungslose Layoutübergänge beim Drehen des Geräts.
- Status beibehalten:Wenn Sie die Aktivitätsinstanz beibehalten, wird das Risiko eines Verlusts des temporären UI-Status bei einem Ereignis wie dem Drehen des Bildschirms verringert. Sie müssen jedoch weiterhin die Beibehaltung des Status bei einem vom System initiierten Prozessabbruch verarbeiten.
Wenn Sie die Neuerstellung von Aktivitäten für bestimmte Konfigurationsänderungen deaktivieren möchten,
fügen Sie den Konfigurationstyp in der
<activity>-Datei im Eintrag AndroidManifest.xml zu android:configChanges hinzu. Mögliche Werte
finden Sie in der Dokumentation zum android:configChanges Attribut.
Der folgende Manifestcode deaktiviert die Neuerstellung von Activity für MyActivity, 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) startet das System Aktivitäten nicht mehr standardmäßig für mehrere Konfigurationsänderungen neu, die in der Regel keine vollständige Neuerstellung der Benutzeroberfläche erfordern.
Stattdessen bleiben Aktivitäten aktiv und erhalten Updates über den
onConfigurationChanged()-Callback.
Zu den spezifischen Konfigurationsänderungen gehören:
CONFIG_KEYBOARDCONFIG_KEYBOARD_HIDDENCONFIG_NAVIGATIONCONFIG_TOUCHSCREENCONFIG_COLOR_MODECONFIG_UI_MODE(nur wenn sich der UI-Modus inUI_MODE_TYPE_DESKändert oder vonUI_MODE_TYPE_DESKzu einem anderen Typ)
Wenn Ihre Anwendung auf einen vollständigen Neustart angewiesen ist, um Ressourcen für diese
Änderungen neu zu laden, müssen Sie sich jetzt explizit für das alte Verhalten entscheiden, indem Sie das
android:recreateOnConfigChanges Attribut in der Manifestdatei verwenden.
Mit dem Attribut können Sie angeben, welche Konfigurationsänderungen einen vollständigen Stopp, die Zerstörung und die Neuerstellung der Aktivität 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 weiterhin korrekt verarbeiten.
Das Configuration-Objekt ist in der Compose-UI-Hierarchie mit
dem Kompositionslokal LocalConfiguration verfügbar. Wenn es sich ändert, werden die Composables, die aus LocalConfiguration.current lesen, neu zusammengesetzt. Informationen zur Funktionsweise von Kompositionslokalen finden Sie unter Lokal begrenzte
Daten mit CompositionLocal.
Beispiel
Im folgenden Beispiel zeigt ein Composable ein Datum in einem bestimmten Format an.
Das Composable reagiert auf Konfigurationsänderungen der Systemsprache, indem es
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))
)
}
Um die Neuerstellung von Activity zu vermeiden, wenn sich die Sprache ändert, muss die Activity, die den Compose-Code hostet, Konfigurationsänderungen der Sprache deaktivieren. Dazu legen Sie android:configChanges auf locale|layoutDirection fest.
Konfigurationsänderungen: Wichtige Konzepte und Best Practices
Das sind die wichtigsten Konzepte, die Sie bei der Arbeit mit Konfigurationsänderungen kennen müssen:
- Konfigurationen:Gerätekonfigurationen definieren, wie die Benutzeroberfläche für den Nutzer angezeigt wird, z. B. Anzeigegröße der App, Bildschirmdichte, Sprache oder Systemdesign.
In Compose können Sie mit
LocalConfigurationauf Konfigurationswerte zugreifen. - Konfigurationsänderungen:Konfigurationen ändern sich durch Nutzerinteraktionen. Der Nutzer kann beispielsweise Geräteeinstellungen ändern oder auf andere Weise mit dem Gerät interagieren. Es gibt keine Möglichkeit, Konfigurationsänderungen zu verhindern.
- Neuerstellung von
Activity:Konfigurationsänderungen führen standardmäßig zur Neuerstellung vonActivity. Dies ist ein integrierter Mechanismus, um den App-Status für die neue Konfiguration neu zu initialisieren. - Zerstörung von
Activity:Bei der Neuerstellung vonActivitywird die alteActivity-Instanz vom System zerstört und an ihrer Stelle 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, verwenden Sie die empfohlenen APIs, 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 als Reaktion auf die neue Konfiguration ordnungsgemäß aktualisiert werden.
Beachten Sie die folgenden Best Practices, um eine gute Nutzererfahrung zu bieten:
- Auf häufige Konfigurationsänderungen vorbereitet sein:Gehen Sie nicht davon aus, dass Konfigurationsänderungen selten oder nie auftreten, unabhängig von API-Level, Formfaktor oder UI-Toolkit. Wenn ein Nutzer eine Konfigurationsänderung verursacht, erwartet er, dass Apps aktualisiert werden und mit der neuen Konfiguration weiterhin korrekt funktionieren.
- Status beibehalten:Der Status des Nutzers darf bei der Neuerstellung von
Activitynicht verloren gehen. Behalten Sie den Status wie unter UI-Status speichern beschrieben mit APIs wieViewModelundrememberSaveablebei. - Deaktivieren nicht als schnelle Lösung verwenden:Deaktivieren Sie die Neuerstellung von
Activitynicht als Abkürzung, um Statusverluste zu vermeiden. Wenn Sie die Neuerstellung von Aktivitäten deaktivieren, müssen Sie die Änderung verarbeiten. Außerdem kann der Status aufgrund der Neuerstellung vonActivitydurch andere Konfigurationsänderungen, Prozessabbrüche oder das 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: Beschränken Sie nicht die Ausrichtung,
das Seitenverhältnis oder die Größenänderung, um Konfigurationsänderungen und
ActivityNeuerstellung zu vermeiden. Dies wirkt sich negativ auf Nutzer aus, die Ihre App auf die von ihnen 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 Bildschirm ausgeführt wird, auf dem Nutzer den Mehrfenstermodus starten 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 liegt vor, wenn aufgrund eines Unterschieds in der Bildschirmgröße, z. B. Breite, Höhe oder kleinste Breite, ein anderer Satz alternativer Ressourcen auf die neue Konfiguration angewendet wird. Zu diesen Ressourcen gehören die, die von der App selbst definiert werden, und die aus ihren Bibliotheken.
Neuerstellung von Aktivitäten für größenbasierte 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
Activity.onConfigurationChanged aufgerufen. Alle Composables, die LocalConfiguration.current lesen, werden automatisch neu zusammengesetzt, um die neue Größe widerzuspiegeln.
Activity recreation ist für größenbasierte Konfigurationsänderungen deaktiviert, wenn
Sie
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
in der Manifestdatei haben.
Zusätzliche Ressourcen
Weitere Informationen zum Umgang mit Konfigurationsänderungen finden Sie in den folgenden zusätzlichen Ressourcen: