Einige Gerätekonfigurationen können sich ändern, während die App ausgeführt wird. Dazu gehören unter anderem:
- App-Anzeigegröße
- Bildschirmausrichtung
- Schriftgröße und ‑stärke
- Sprache
- Dunkler Modus im Vergleich zum hellen Modus
- Verfügbarkeit der Tastatur
Die meisten dieser Konfigurationsänderungen sind auf Nutzerinteraktionen zurückzuführen. Wenn Sie das Gerät beispielsweise drehen oder zusammenfalten, ändert sich die Menge an Bildschirmfläche, die Ihrer App zur Verfügung steht. Wenn Sie Geräteeinstellungen wie die Schriftgröße, die Sprache oder das bevorzugte Design ändern, ändern sich die entsprechenden Werte im Configuration-Objekt.
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 Activity-Neuerstellung.
Aktivität zur Erholung
Das System erstellt ein Activity neu, wenn eine Konfigurationsänderung erfolgt. 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.
Durch das Verhalten beim Neuerstellen 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 Freizeitaktivitäten
Stellen Sie sich eine TextView vor, in der ein statischer Titel mit android:text="@string/title" angezeigt wird, wie in einer XML-Layoutdatei definiert. Wenn die Ansicht erstellt wird, wird der Text genau einmal basierend auf der aktuellen Sprache festgelegt. Wenn sich die Sprache ändert, wird die Aktivität vom System neu erstellt. Das System erstellt die Ansicht neu und initialisiert sie mit dem richtigen Wert basierend auf der neuen Sprache.
Beim Neuerstellen werden auch alle Status gelöscht, die als Felder in Activity oder in einem der enthaltenen Fragment-, View- oder anderen Objekte gespeichert sind. Das liegt daran, dass beim Neuerstellen von Activity eine völlig neue Instanz von Activity und der Benutzeroberfläche erstellt wird. Außerdem ist die alte Activity nicht mehr sichtbar oder gültig. Alle verbleibenden Verweise darauf oder auf die darin enthaltenen Objekte sind daher nicht mehr aktuell. Sie können zu Fehlern, Speicherlecks und Abstürzen führen.
Erwartungen der Nutzer
Nutzer einer App erwarten, dass der Status beibehalten wird. Wenn ein Nutzer ein Formular ausfüllt und eine andere App im Multifenstermodus öffnet, um Informationen abzurufen, ist es schlecht, 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 für eine konsistente Nutzererfahrung sorgen.
Um zu prüfen, ob der Status in Ihrer Anwendung beibehalten wird, können Sie Aktionen ausführen, die Konfigurationsänderungen verursachen, sowohl wenn sich die App im Vordergrund als auch im Hintergrund befindet. Diese Aktivitäten umfassen:
- Gerät drehen
- Mehrfenstermodus starten
- Größe der Anwendung im Mehrfenstermodus oder in einem Freiform-Fenster ändern
- Falten eines faltbaren Geräts mit mehreren Displays
- Ändern des Systemdesigns, z. B. vom dunklen in den hellen Modus
- Schriftgröße ändern
- System- oder App-Sprache ändern
- Hardwaretastatur anschließen oder trennen
- Dockingstation anschließen oder trennen
Es gibt drei primäre Ansätze, mit denen Sie den relevanten Status bei der Neuerstellung von Activity beibehalten können. Welche Methode Sie verwenden, hängt davon ab, welche Art von Status Sie beibehalten möchten:
- Lokale Persistenz, um das Beenden von Prozessen bei komplexen oder großen Daten zu verarbeiten.
Die dauerhafte lokale Speicherung umfasst Datenbanken oder
DataStore. - Beibehaltene Objekte wie
ViewModel-Instanzen, um UI-bezogene Status im Arbeitsspeicher zu verarbeiten, während der Nutzer die App aktiv verwendet. - Gespeicherter Instanzstatus, um systeminitiierte Prozessbeendigungen zu verarbeiten und den transienten Status beizubehalten, der von Nutzereingaben oder der Navigation abhängt.
Weitere Informationen zu den APIs für die einzelnen Fälle und dazu, wann die Verwendung der jeweiligen API angebracht ist, finden Sie unter UI-Zustände speichern.
Erstellung von Aktivitäten einschränken
Sie können verhindern, dass Aktivitäten bei bestimmten Konfigurationsänderungen automatisch neu erstellt werden.
Bei der Neuerstellung von Activity wird die gesamte Benutzeroberfläche und alle Objekte, die von Activity abgeleitet sind, neu erstellt. Dafür kann es gute Gründe geben. Beispielsweise muss Ihre App Ressourcen bei einer bestimmten Konfigurationsänderung möglicherweise nicht aktualisieren oder es gibt eine Leistungsbeschränkung. In diesem Fall können Sie deklarieren, dass Ihre Aktivität die Konfigurationsänderung selbst verarbeitet, und verhindern, dass das System Ihre Aktivität neu startet.
Wenn Sie die Neuerstellung von Aktivitäten für bestimmte Konfigurationsänderungen deaktivieren möchten, fügen Sie den Konfigurationstyp dem android:configChanges-Eintrag im <activity>-Eintrag in Ihrer AndroidManifest.xml-Datei 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">
Einige Konfigurationsänderungen führen immer zu einem Neustart der Aktivität. Sie können sie nicht deaktivieren. So können Sie beispielsweise die in Android 12L (API-Level 32) eingeführte Änderung der dynamischen Farben nicht deaktivieren.
Auf Konfigurationsänderungen im View-System reagieren
Wenn im View-System eine Konfigurationsänderung erfolgt, für die Sie die Neuerstellung von Activity deaktiviert haben, wird für die Aktivität Activity.onConfigurationChanged() aufgerufen. Alle angehängten Ansichten erhalten ebenfalls einen Aufruf an View.onConfigurationChanged(). Bei Konfigurationsänderungen, die Sie nicht android:configChanges hinzugefügt haben, wird die Aktivität wie gewohnt neu erstellt.
Die Callback-Methode onConfigurationChanged() empfängt ein Configuration-Objekt, das die neue Gerätekonfiguration angibt. Lesen Sie die Felder im Configuration-Objekt, um die neue Konfiguration zu ermitteln. Aktualisieren Sie die Ressourcen, die Sie in Ihrer Benutzeroberfläche verwenden, um die nachfolgenden Änderungen vorzunehmen. Wenn das System diese Methode aufruft, wird das Resources-Objekt Ihrer Aktivität aktualisiert, um Ressourcen basierend auf der neuen Konfiguration zurückzugeben. So können Sie Elemente der Benutzeroberfläche zurücksetzen, ohne dass das System Ihre Aktivität neu startet.
Die folgende onConfigurationChanged()-Implementierung prüft beispielsweise, ob eine Tastatur verfügbar ist:
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}
}
Java
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a keyboard is available
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
}
}
Wenn Sie Ihre Anwendung aufgrund dieser Konfigurationsänderungen nicht aktualisieren müssen, können Sie onConfigurationChanged() stattdessen nicht implementieren. In diesem Fall werden alle Ressourcen, die vor der Konfigurationsänderung verwendet wurden, weiterhin verwendet und Sie haben nur den Neustart Ihrer Aktivität vermieden. Beispielsweise soll eine TV-App möglicherweise nicht reagieren, wenn eine Bluetooth-Tastatur angeschlossen oder getrennt wird.
Status beibehalten
Wenn Sie diese Technik verwenden, müssen Sie den Status während des normalen Aktivitätslebenszyklus beibehalten. Das hat folgende Gründe:
- Unvermeidliche Änderungen:Konfigurationsänderungen, die Sie nicht verhindern können, können Ihre Anwendung neu starten.
- Prozessbeendigung:Ihre Anwendung muss in der Lage sein, vom System initiierte Prozessbeendigungen zu verarbeiten. Wenn der Nutzer Ihre Anwendung verlässt und die App in den Hintergrund verschoben wird, kann das System die App beenden.
Auf Konfigurationsänderungen in Jetpack Compose reagieren
Mit Jetpack Compose kann Ihre App einfacher auf Konfigurationsänderungen reagieren.
Wenn Sie 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 Objekt Configuration ist in der Compose-UI-Hierarchie mit dem lokalen LocalConfiguration-Composer verfügbar. Immer wenn sich der Wert ändert, werden zusammensetzbare Funktionen, die LocalConfiguration.current lesen, neu zusammengesetzt. Informationen zur Funktionsweise von CompositionLocals finden Sie unter Lokal begrenzte Daten mit CompositionLocal.
Beispiel
Im folgenden Beispiel wird in einem Composable ein Datum in einem bestimmten Format angezeigt.
Das Composable reagiert auf Änderungen an der Systemgebietsschema-Konfiguration, indem ConfigurationCompat.getLocales() mit LocalConfiguration.current aufgerufen wird.
@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 Activity nicht neu erstellt wird, wenn sich das Gebietsschema ändert, muss das Activity, in dem der Compose-Code gehostet wird, die Verarbeitung von Änderungen an der Gebietsschemakonfiguration deaktivieren. Legen Sie dazu android:configChanges auf locale|layoutDirection fest.
Konfigurationsänderungen: Wichtige Konzepte und Best Practices
Dies sind die wichtigsten Konzepte, die Sie bei der Arbeit an Konfigurationsänderungen kennen sollten:
- Konfigurationen:Gerätekonfigurationen definieren, wie die Benutzeroberfläche für den Nutzer angezeigt wird, z. B. die Anzeigegröße der App, die Sprache oder das Systemdesign.
- Konfigurationsänderungen:Konfigurationen ändern sich durch Nutzerinteraktion. Der Nutzer ändert beispielsweise die Geräteeinstellungen oder die Art und Weise, wie er das Gerät physisch bedient. Konfigurationsänderungen lassen sich nicht verhindern.
Activityneu erstellen:Konfigurationsänderungen führen standardmäßig dazu, dassActivityneu erstellt wird. Dies ist ein integrierter Mechanismus zum Reinitialisieren des App-Status für die neue Konfiguration.Activity-Löschung:Durch die Neuerstellung derActivitywird die alteActivity-Instanz gelöscht und eine neue an ihrer Stelle erstellt. Die alte Instanz ist jetzt überflüssig. Alle verbleibenden Verweise darauf führen zu Speicherlecks, Programmfehlern oder Abstürzen.- Status:Der Status in der alten
Activity-Instanz ist in der neuenActivity-Instanz nicht vorhanden, da es sich um zwei verschiedene Objektinstanzen handelt. Speichern Sie den Status der App und des Nutzers, wie unter UI-Status speichern beschrieben. - Deaktivieren:Wenn Sie die Neuerstellung von Aktivitäten für eine bestimmte Art von Konfigurationsänderung deaktivieren, kann das eine Optimierung sein. Dazu muss Ihre App entsprechend der neuen Konfiguration aktualisiert werden.
Für eine gute Nutzererfahrung sollten Sie die folgenden Best Practices beachten:
- Häufige Konfigurationsänderungen einkalkulieren:Gehen Sie 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 bei, wie unter UI-Status speichern beschrieben. - Schnelle Lösungen vermeiden:Deaktivieren Sie die Neuerstellung von
Activitynicht, um Datenverlust zu vermeiden. Wenn Sie die Neuerstellung von Aktivitäten deaktivieren, müssen Sie das Versprechen einhalten, die Änderung zu verarbeiten. Der Status kann jedoch weiterhin aufgrund der Neuerstellung vonActivitydurch andere Konfigurationsänderungen, das Beenden des Prozesses oder das Schließen der App verloren gehen. Es ist nicht möglich, die Neuerstellung vonActivityvollständig zu deaktivieren. Behalten Sie den Status bei, wie unter UI-Status speichern beschrieben. - Konfigurationsänderungen nicht vermeiden:Beschränken Sie die Ausrichtung, das Seitenverhältnis oder die Größenänderung nicht, um Konfigurationsänderungen und die Neuerstellung von
Activityzu 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 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 Arten von Größenänderungen: signifikante und nicht signifikante. Eine erhebliche Größenänderung liegt vor, wenn aufgrund einer Änderung der Bildschirmgröße, z. B. der Breite, Höhe oder kleinsten Breite, ein anderer Satz alternativer Ressourcen für die neue Konfiguration gilt. Dazu gehören Ressourcen, die von der App selbst definiert werden, und Ressourcen aus den Bibliotheken der App.
Aktivitätserstellung für größenbasierte Konfigurationsänderungen einschränken
Wenn Sie die Neuerstellung von Activity für größenbasierte Konfigurationsänderungen deaktivieren, wird das Activity nicht neu erstellt. Stattdessen wird Activity.onConfigurationChanged() aufgerufen. Alle angehängten Ansichten empfangen einen Aufruf an View.onConfigurationChanged().
Die Neuerstellung von Activity ist für größenbasierte Konfigurationsänderungen deaktiviert, wenn Sie android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" in Ihrer Manifestdatei haben.
Aktivitätsneuerstellung bei größenbasierten Konfigurationsänderungen zulassen
Unter Android 7.0 (API-Level 24) und höher erfolgt die Neuerstellung von Activity nur bei größenbasierten Konfigurationsänderungen, wenn die Größenänderung erheblich ist. Wenn das System aufgrund einer unzureichenden Größe kein Activity neu erstellt, ruft es stattdessen möglicherweise Activity.onConfigurationChanged() und View.onConfigurationChanged() auf.
Bei den Activity- und View-Callbacks sind einige Einschränkungen zu beachten, wenn die Activity nicht neu erstellt wird:
- Unter Android 11 (API-Level 30) bis Android 13 (API-Level 33) wird
Activity.onConfigurationChanged()nicht aufgerufen. - Es gibt ein bekanntes Problem, bei dem
View.onConfigurationChanged()in einigen Fällen unter Android 12L (API-Level 32) und frühen Versionen von Android 13 (API-Level 33) möglicherweise nicht aufgerufen wird. Weitere Informationen finden Sie in diesem öffentlichen Problem. Dieses Problem wurde in späteren Android 13-Versionen und in Android 14 behoben.
Für Code, der auf das Abhören von größenbasierten Konfigurationsänderungen angewiesen ist, empfehlen wir die Verwendung eines Utility-View mit einem überschriebenen View.onConfigurationChanged() anstelle der Neuerstellung von Activity oder Activity.onConfigurationChanged().