Obsługa zmian konfiguracji

Niektóre konfiguracje urządzenia mogą się zmieniać podczas działania aplikacji. Obejmują one m.in.:

  • Rozmiar wyświetlania aplikacji
  • Orientacja ekranu
  • Rozmiar i grubość czcionki
  • Język
  • Tryb ciemny a tryb jasny
  • Dostępność klawiatury

Większość tych zmian konfiguracji następuje w wyniku interakcji użytkownika. Na przykład obrócenie lub złożenie urządzenia zmienia ilość miejsca na ekranie dostępnego dla aplikacji. Podobnie zmiana ustawień urządzenia, takich jak rozmiar czcionki, język lub preferowany motyw, zmienia odpowiednie wartości w obiekcie Configuration.

Te parametry zwykle wymagają wystarczająco dużych zmian w interfejsie aplikacji, aby platforma Android miała specjalny mechanizm, który reaguje na ich zmianę. Ten mechanizm to Activityrekonstrukcja.

Odtwarzanie aktywności

System odtwarza Activity, gdy nastąpi zmiana konfiguracji. W tym celu wywołuje funkcję onDestroy i niszczy istniejącą instancję Activity. Następnie tworzy nową instancję za pomocą funkcji onCreate, a ta nowa instancja Activity jest inicjowana z nową, zaktualizowaną konfiguracją. Oznacza to również, że system odtwarza interfejs użytkownika z nową konfiguracją.

Zwykle Activity jest hostem dla funkcji kompozycyjnych. Gdy Activity zostanie ponownie utworzony, Compose również ponownie utworzy interfejs użytkownika, używając nowych wartości konfiguracji.

Ponowne tworzenie pomaga aplikacji dostosowywać się do nowych konfiguracji, ponieważ automatycznie przeładowuje ją za pomocą alternatywnych zasobów pasujących do nowej konfiguracji urządzenia.

Przykład dotyczący rekreacji

Rozważ użycie funkcji kompozycyjnej, która wyświetla statyczny tytuł za pomocą zasobu tekstowego:

// In the res/values/strings.xml file
// <string name="compose">Jetpack Compose</string>

// In your Compose code
Text(
    text = stringResource(R.string.compose)
)

Gdy tworzony jest element Activity, funkcja kompozycyjna Text odczytuje bieżącą konfigurację (np. język) i wybiera odpowiedni zasób w postaci ciągu znaków.

Jeśli język się zmieni, system ponownie utworzy aktywność. W takiej sytuacji funkcja Pisanie od nowa tworzy interfejs. Ponieważ funkcja stringResource odczytuje bieżącą konfigurację, tytuł automatycznie aktualizuje się do prawidłowej zlokalizowanej wartości.

Ponowne utworzenie powoduje też wyczyszczenie wszystkich stanów przechowywanych jako pola w obiekcie Activity.

Aby zachować stan interfejsu podczas zmian konfiguracji, używaj zalecanych wzorców zarządzania stanem. Do danych i logiki biznesowej używaj ViewModel, a do stanu na poziomie interfejsu – rememberSaveable. Dzięki tym mechanizmom stan przetrwa ponowne utworzenie Activity, a interfejs zostanie zaktualizowany, aby odzwierciedlać nową konfigurację.

Więcej informacji o zapisywaniu stanu w Compose znajdziesz w artykule Zapisywanie stanu interfejsu w Compose.

.

Oczekiwania użytkowników

Użytkownik aplikacji oczekuje, że stan zostanie zachowany. Jeśli użytkownik wypełnia formularz i otwiera inną aplikację w trybie wielu okien, aby sprawdzić informacje, a po powrocie do formularza okazuje się, że został on wyczyszczony lub że użytkownik został przeniesiony w inne miejsce w aplikacji, jest to negatywne doświadczenie. Jako deweloper musisz zapewnić spójne wrażenia użytkownika poprzez zmiany konfiguracji i ponowne tworzenie aktywności.

Aby sprawdzić, czy stan jest zachowywany w aplikacji, możesz wykonać działania powodujące zmiany konfiguracji zarówno wtedy, gdy aplikacja jest na pierwszym planie, jak i w tle. Dotyczy to następujących czynności:

  • Obracanie urządzenia
  • Włączanie trybu wielu okien
  • Zmiana rozmiaru aplikacji w trybie wielu okien lub w oknie o dowolnym kształcie
  • Składanie urządzenia składanego z wieloma wyświetlaczami
  • zmiana motywu systemu, np. z trybu ciemnego na jasny;
  • Zmiana rozmiaru czcionki
  • Zmiana języka systemu lub aplikacji
  • Podłączanie i odłączanie klawiatury sprzętowej
  • Podłączanie i odłączanie stacji dokującej

Istnieje kilka sposobów zachowania odpowiedniego stanu podczas Activityponownego tworzenia. Wybór zależy od typu stanu, który chcesz zachować:

  • Lokalne utrwalanie do obsługi śmierci procesu w przypadku złożonych lub dużych danych. Trwałe przechowywanie lokalne obejmuje bazy danych lub DataStore.
  • Obiekty zachowane, takie jak instancje ViewModel, do obsługi stanu związanego z interfejsem w pamięci, gdy użytkownik aktywnie korzysta z aplikacji.
  • rememberSaveable – aby zachować przejściowy stan interfejsu w przypadku zmian konfiguracji i śmierci procesu zainicjowanej przez system. Jest to odpowiednie w przypadku stanu, który zależy od danych wejściowych użytkownika, pozycji przewijania lub nawigacji, ale nie należy do ViewModel.

Szczegółowe informacje o interfejsach API dla każdego z tych przypadków oraz o tym, kiedy należy ich używać, znajdziesz w artykule Zapisywanie stanów interfejsu.

Ograniczanie ponownego tworzenia aktywności

Możesz zapobiec automatycznemu ponownemu tworzeniu aktywności w przypadku niektórych zmian konfiguracji. W nowoczesnych aplikacjach opartych wyłącznie na Compose interfejs jest ponownie komponowany w obu przypadkach, ale zalecamy bezpośrednie obsługiwanie zmiany konfiguracji.

Domyślnie zmiana konfiguracji powoduje, że system niszczy i ponownie tworzy aktywność, w tym interfejs i wszystkie obiekty pochodne. Jeśli zadeklarujesz, że aktywność sama obsługuje zmianę konfiguracji, system temu zapobiegnie. Zamiast tego aktualizowany jest tylko obiekt Configuration, a funkcja Compose ponownie tworzy interfejs z nowymi wartościami.

Bezpośrednie obsługiwanie zmian konfiguracji w Compose ma kilka zalet:

  • Lepsza wydajność: ponowne komponowanie interfejsu jest mniej kosztowne niż pełny cykl ponownego tworzenia aktywności, zwłaszcza w przypadku drobnych zmian.
  • Płynne animacje: unikanie ponownego uruchamiania aktywności umożliwia ciągłe animacje podczas zmian konfiguracji, np. płynne przejścia układu podczas obracania urządzenia.
  • Zachowywanie stanu: zachowywanie instancji aktywności zmniejsza ryzyko utraty tymczasowego stanu interfejsu podczas zdarzenia takiego jak obracanie ekranu. Pamiętaj, że musisz nadal obsługiwać zachowywanie stanu w przypadku zakończenia procesu zainicjowanego przez system.

Aby wyłączyć ponowne tworzenie aktywności w przypadku określonych zmian konfiguracji, dodaj typ konfiguracji do parametru android:configChanges we wpisie <activity> w pliku AndroidManifest.xml. Możliwe wartości znajdziesz w dokumentacji atrybutu android:configChanges.

Ten kod pliku manifestu wyłącza Activity ponowne tworzenie MyActivity, gdy zmienia się orientacja ekranu i dostępność klawiatury:

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

Reagowanie na zmiany konfiguracji

Jetpack Compose ułatwia reagowanie aplikacji na zmiany konfiguracji. Jeśli jednak wyłączysz Activity ponowne tworzenie w przypadku wszystkich zmian konfiguracji, w których jest to możliwe, aplikacja nadal musi prawidłowo obsługiwać zmiany konfiguracji.

Obiekt Configuration jest dostępny w hierarchii interfejsu Compose z lokalnym komponentem LocalConfiguration. Gdy się zmieni, funkcje kompozycyjne odczytujące wartość LocalConfiguration.current zostaną ponownie skomponowane. Więcej informacji o tym, jak działają lokalne kompozycje, znajdziesz w artykule Dane o zasięgu lokalnym z użyciem CompositionLocal.

Przykład

W tym przykładzie funkcja kompozycyjna wyświetla datę w określonym formacie. Kompozycja reaguje na zmiany konfiguracji języka systemu, wywołując funkcję ConfigurationCompat.getLocales z parametrem LocalConfiguration.current.

@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))
    )
}

Aby uniknąć ponownego tworzenia Activity po zmianie ustawień regionalnych, host Activity zawierający kod Compose musi zrezygnować ze zmian konfiguracji ustawień regionalnych. Aby to zrobić, ustaw android:configChanges na locale|layoutDirection.

Zmiany konfiguracji: kluczowe pojęcia i sprawdzone metody

Oto najważniejsze pojęcia, które musisz znać, gdy pracujesz nad zmianami w konfiguracji:

  • Konfiguracje: konfiguracje urządzenia określają sposób wyświetlania interfejsu użytkownikowi, np. rozmiar wyświetlania aplikacji, ustawienia regionalne lub motyw systemu. W Compose możesz uzyskać dostęp do wartości konfiguracji za pomocą LocalConfiguration.
  • Zmiany konfiguracji: konfiguracje zmieniają się w wyniku interakcji użytkownika. Na przykład użytkownik może zmienić ustawienia urządzenia lub sposób fizycznego korzystania z niego. Nie można zapobiec zmianom konfiguracji.
  • Activity ponowne tworzenie: zmiany konfiguracji domyślnie powodują ponowne utworzenie Activity. Jest to wbudowany mechanizm ponownego inicjowania stanu aplikacji w przypadku nowej konfiguracji.
  • Activity zniszczenie: Activity ponowne utworzenie powoduje zniszczenie przez system starej instancji Activity i utworzenie w jej miejsce nowej. Stara instancja jest teraz przestarzała. Unikaj zachowywania odwołań do obiektów o zakresie cyklu życia poza ich zamierzonym zakresem.
  • Stan: stan w starej instancji Activity nie występuje w nowej instancji Activity, ponieważ są to 2 różne instancje obiektu. Zamiast wiązać stan z aktywnością, użyj zalecanych interfejsów API, aby zachować stan aplikacji i użytkownika zgodnie z opisem w sekcji Zapisywanie stanów interfejsu.
  • Rezygnacja: rezygnacja z ponownego tworzenia aktywności w przypadku zmiany typu konfiguracji wymaga, aby aplikacja prawidłowo reagowała na nową konfigurację.

Aby zapewnić użytkownikom wygodę, postępuj zgodnie z tymi sprawdzonymi metodami:

  • Przygotuj się na częste zmiany konfiguracji: nie zakładaj, że zmiany konfiguracji są rzadkie lub nigdy się nie zdarzają, niezależnie od poziomu interfejsu API, rodzaju urządzenia czy zestawu narzędzi interfejsu. Gdy użytkownik spowoduje zmianę konfiguracji, oczekuje, że aplikacje zostaną zaktualizowane i będą nadal działać prawidłowo w nowej konfiguracji.
  • Zachowaj stan: nie trać stanu użytkownika, gdy nastąpi Activity ponowne utworzenie komponentu. Zachowaj stan zgodnie z opisem w artykule Zapisywanie stanów interfejsu za pomocą interfejsów API, takich jak ViewModelrememberSaveable.
  • Unikaj rezygnacji jako szybkiego rozwiązania: nie rezygnuj z Activity ponownego tworzenia jako skrótu, aby uniknąć utraty stanu. Rezygnacja z ponownego tworzenia aktywności wymaga spełnienia obietnicy obsługi zmiany. Stan może zostać utracony z powodu ponownego tworzenia Activity w wyniku innych zmian konfiguracji, zakończenia procesu lub zamknięcia aplikacji. Całkowite wyłączenie ponownego tworzenia Activity jest niemożliwe. Zachowaj stan zgodnie z opisem w sekcji Zapisywanie stanów interfejsu.
  • Nie unikaj zmian konfiguracji: nie ograniczaj orientacji, współczynnika proporcji ani możliwości zmiany rozmiaru, aby uniknąć zmian konfiguracji i Activity ponownego tworzenia. Ma to negatywny wpływ na użytkowników, którzy chcą korzystać z aplikacji w preferowany przez siebie sposób.

Obsługa zmian konfiguracji zależnych od rozmiaru

Zmiany konfiguracji oparte na rozmiarze mogą nastąpić w dowolnym momencie i są bardziej prawdopodobne, gdy aplikacja jest uruchamiana na urządzeniu z dużym ekranem, na którym użytkownicy mogą włączyć tryb wielu okien. Oczekują oni, że aplikacja będzie dobrze działać w tym środowisku.

Wyróżniamy 2 rodzaje zmian rozmiaru: znaczące i nieznaczące. Znacząca zmiana rozmiaru to taka, w przypadku której do nowej konfiguracji stosowany jest inny zestaw zasobów alternatywnych ze względu na różnicę w rozmiarze ekranu, np. szerokości, wysokości lub najmniejszej szerokości. Zasoby te obejmują te, które są zdefiniowane przez samą aplikację, oraz te, które pochodzą z jej bibliotek.

Ograniczanie ponownego tworzenia aktywności w przypadku zmian konfiguracji opartych na rozmiarze

Gdy wyłączysz Activity odtwarzanie w przypadku zmian konfiguracji opartych na rozmiarze, system nie odtworzy Activity. Zamiast tego otrzyma połączenie na numer Activity.onConfigurationChanged. Wszystkie funkcje kompozycyjne odczytujące wartość LocalConfiguration.current automatycznie ponownie się skomponują, aby odzwierciedlić nowy rozmiar.

Odtwarzanie Activity jest wyłączone w przypadku zmian konfiguracji opartych na rozmiarze, gdy w pliku manifestu masz android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout".

Dodatkowe materiały

Więcej informacji o obsłudze zmian konfiguracji znajdziesz w tych dodatkowych materiałach:

Dokumentacja

Wyświetla treści