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 werden durch eine Nutzerinteraktion ausgelöst. Wenn Sie beispielsweise das Gerät drehen oder zusammenklappen, ä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 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 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 an die neue Konfiguration angepasst wird.

Weitere Informationen zum Speichern des Status in Compose finden Sie unter UI-Status in Compose speichern.

Erwartungen der Nutzer

Nutzer erwarten, dass der Status einer App beibehalten wird. Wenn ein Nutzer ein Formular ausfüllt und eine andere App im Mehrfenstermodus ö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 Aktionen 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
  • Systemdesign ändern, z. B. dunkler Modus im Vergleich zum hellen Modus
  • Schriftgröße ändern
  • System- oder App-Sprache ändern
  • Hardwaretastatur anschließen oder trennen
  • Dockingstation anschließen oder trennen

Es gibt verschiedene 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 Behandlung von Prozessabstürzen 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 systemseitigen Prozessabstürzen. Dies ist für den Status geeignet, der von der Nutzereingabe, der Scrollposition oder der Navigation abhängt, aber nicht in eine ViewModel gehört.

Weitere 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 zu löschen und neu zu erstellen, einschließlich der Benutzeroberfläche und aller Objekte, die von der Activity 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 bietet 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 Zustands bei systemseitiger 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 dem Eintrag android:configChanges in Ihrer AndroidManifest.xml Datei 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">

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 Composable-Funktionen, die aus LocalConfiguration.current lesen, neu zusammengesetzt. Informationen zur Funktionsweise von Kompositionslokalen 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 dem Nutzer angezeigt wird, z. B. Anzeigegröße der App, Sprache oder Systemdesign. In Compose können Sie mit LocalConfiguration auf Konfigurationswerte zugreifen.
  • Konfigurationsänderungen:Konfigurationen ändern sich durch Nutzerinteraktionen. Beispielsweise kann der Nutzer Geräteeinstellungen ändern oder die Art und Weise, wie er mit dem Gerät interagiert. Konfigurationsänderungen können nicht verhindert werden.
  • 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. Für die meisten Compose-Apps wird dies nicht empfohlen.

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 ordnungsgemäß 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 Zustand aufgrund der Neuerstellung von Activity durch andere Konfigurationsänderungen, Prozessbeendigung oder das 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: 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 vom System 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 zur Verarbeitung von Konfigurationsänderungen finden Sie in den folgenden zusätzlichen Ressourcen:

Dokumentation

Ansichteninhalte