Umgang mit Konfigurationsänderungen

Einige Gerätekonfigurationen können sich ändern, während die App ausgeführt wird. Dazu gehören unter anderem:

  • Anzeigegröße der App
  • 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 eine Nutzerinteraktion zurückzuführen. Wenn Sie beispielsweise das Gerät drehen oder zusammenklappen, ändert sich der für Ihre App verfügbare Bildschirmplatz. Wenn Sie Geräteeinstellungen wie die Schriftgröße, die Sprache oder das bevorzugte Design ändern, ändern sich auch 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 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 gesamte 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 sich die App im Vordergrund als auch im Hintergrund befindet. Diese Aktivitäten umfassen:

  • Drehen des Geräts
  • Starten des Mehrfenstermodus
  • Ändern der Größe der Anwendung im Mehrfenstermodus oder in einem Freiform-Fenster
  • Zusammenklappen eines faltbaren Geräts mit mehreren Displays
  • Ändern des Systemdesigns, z. B. vom dunklen in den hellen Modus
  • Ändern der Schriftgröße
  • Ändern der System- oder App-Sprache
  • Verbinden oder Trennen einer Hardwaretastatur
  • Verbinden oder Trennen einer Dockingstation

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 zur Verarbeitung von Prozessbeendigung bei komplexen oder großen Daten. Permanenter lokaler Speicher umfasst Datenbanken oder DataStore.
  • Beibehaltene Objekte wie ViewModel-Instanzen zur Verarbeitung des UI-bezogenen Status im Arbeitsspeicher, während der Nutzer die App aktiv verwendet.
  • rememberSaveable zum Beibehalten des temporären UI-Status bei Konfigurationsänderungen und systemseitiger Prozessbeendigung. Dies ist für Status geeignet, der von der Nutzereingabe, der Scrollposition oder der Navigation abhängt, aber nicht in eine ViewModel gehö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 führt eine Konfigurationsänderung dazu, dass das System die Aktivität zerstört und neu erstellt, einschließlich der Benutzeroberfläche und aller Objekte, die von der Aktivität abgeleitet wurden. 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.
  • Statusbeibehaltung:Durch das Beibehalten der Aktivitätsinstanz 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 Statusbeibehaltung für die systemseitige Prozessbeendigung 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 android:configChanges zu AndroidManifest.xml hinzu. Mögliche Werte finden Sie in der Dokumentation für das 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:

Wenn Ihre Anwendung auf einem vollständigen Neustart basiert, 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 lokalen LocalConfiguration-Composable verfügbar. Wenn es sich ändert, werden Composable-Funktionen, die aus LocalConfiguration.current lesen, neu zusammengesetzt. Informationen zur Funktionsweise von lokalen Composables finden Sie unter Daten mit lokalem Gültigkeitsbereich mit CompositionLocal.

Beispiel

Im folgenden Beispiel zeigt ein Composable ein Datum in einem bestimmten Format an. Das Composable reagiert auf Konfigurationsänderungen des Systemgebietsschemas, 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 das Gebietsschema ändert, muss die Activity, die den Compose-Code hostet, die Konfigurationsänderungen des Gebietsschemas 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 an Konfigurationsänderungen kennen müssen:

  • 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. In Compose können Sie mit LocalConfiguration auf 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 von Activity. Dies ist ein integrierter Mechanismus, um den App-Status für die neue Konfiguration neu zu initialisieren.
  • Zerstörung von Activity:Bei der Neuerstellung von Activity wird die alte Activity-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 neuen Activity-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 Activity nicht verloren gehen. Behalten Sie den Status wie unter UI-Status speichern beschrieben mit APIs wie ViewModel und rememberSaveable bei.
  • Deaktivieren nicht als schnelle Lösung verwenden:Deaktivieren Sie die Neuerstellung von Activity nicht 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 von Activity durch andere Konfigurationsänderungen, Prozessbeendigung oder Schließen der App verloren gehen. Es ist nicht möglich, die Neuerstellung von Activity vollstä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 Activity Neuerstellung 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: bedeutende und unbedeutende. Eine bedeutende 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 auf die neue Konfiguration angewendet wird. Zu diesen Ressourcen gehören sowohl die von der App selbst definierten als auch 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 is disabled for size-based configuration changes when you have android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" in your manifest file.

Zusätzliche Ressourcen

Weitere Informationen zum Umgang mit Konfigurationsänderungen finden Sie in den folgenden zusätzlichen Ressourcen:

Dokumentation

Inhalte in Ansichten