Stan fragmentu mogą wpływać różne operacje systemu Android. Aby zachować stan użytkownika, platforma Androida automatycznie zapisuje i przywraca fragmenty oraz stos apek. Dlatego musisz się upewnić, że wszystkie dane we fragmencie również zostały zapisane i przywrócone.
Tabela poniżej zawiera operacje, które powodują utratę stanu przez fragment, oraz informacje o tym, czy różne typy stanu są zachowywane podczas tych zmian. Typy stanów wymienione w tabeli:
- Zmienne: zmienne lokalne w fragmentach.
- Stan widoku: dowolne dane, które należą do co najmniej jednego widoku danych we fragmencie.
- SavedState: dane związane z tą instancją fragmentu, które powinny zostać zapisane w
onSaveInstanceState()
. - NonConfig: dane pobrane ze źródła zewnętrznego, np. z serwera lub lokalnego repozytorium, albo dane utworzone przez użytkownika, które po zatwierdzeniu są wysyłane na serwer.
Zmienne są często traktowane tak samo jak SavedState, ale w poniższej tabeli przedstawiono między nimi różnice, aby zaprezentować wpływ na każdą z nich różnych operacji.
Operacja | Zmienne | Wyświetlanie stanu | SavedState | Brak konfiguracji |
---|---|---|---|---|
Dodano do grupy elementów do cofnięcia | ✓ | ✓ | x | ✓ |
Zmiana konfiguracji | x | ✓ | ✓ | ✓ |
Proces śmierci/wypoczynku | x | ✓ | ✓ | ✓* |
Usunięto nie dodano do grupy wstecz | x | x | x | x |
Host zakończony | x | x | x | x |
* Stan niebędący stanem konfiguracji może być zachowany po zakończeniu działania procesu za pomocą modułu zapisanego stanu dla ViewModel.
Tabela 1.: różne operacje niszczenia fragmentów i ich wpływ na różne typy stanów.
Przyjrzyjmy się konkretnemu przykładowi. Weźmy na przykład ekran, który generuje losowy ciąg znaków, wyświetla go w TextView
i umożliwia jego edycję przed wysłaniem go do znajomego:
W tym przykładzie zakładamy, że po naciśnięciu przez użytkownika przycisku edycji aplikacja wyświetla widok EditText
, w którym użytkownik może edytować wiadomość. Jeśli użytkownik kliknie ANULUJ, widok EditText
powinien zostać wyczyszczony i był ustawiony na View.GONE
. Taki ekran może wymagać zarządzania 4 rodzajami danych, aby zapewnić płynne działanie:
Dane | Typ | Typ stanu | Opis |
---|---|---|---|
seed |
Long |
NonConfig | Ziarno służące do losowego generowania nowych dobrych uczynków. Generowany podczas tworzenia ViewModel . |
randomGoodDeed |
String |
SavedState + zmienna | Generowany, gdy fragment jest tworzony po raz pierwszy.
randomGoodDeed jest zapisywany, aby użytkownicy widzieli tę samą losową dobrą rzecz nawet po zakończeniu i powtórnym uruchomieniu procesu. |
isEditing |
Boolean |
SavedState + Variable | Flaga logiczna ustawiona na true , gdy użytkownik rozpoczyna edycję.
Pole isEditing jest zapisywane, aby obszar ekranu, na którym można edytować dane, był widoczny po odtworzeniu fragmentu. |
Edytowany tekst | Editable |
Wyświetl stan (właściciel: EditText ) |
Edytowany tekst w widoku EditText .
Widok EditText zapisuje ten tekst, aby mieć pewność, że wprowadzane przez użytkownika zmiany nie zostaną utracone. |
Tabela 2. Stany, którymi musi zarządzać aplikacja losowego generatora tekstu.
W następnych sekcjach opisaliśmy, jak prawidłowo zarządzać stanem danych za pomocą operacji niszczycielskich.
Wyświetlanie stanu
Wyświetlenia odpowiadają za zarządzanie własnym stanem. Jeśli na przykład widok przyjmuje dane wejściowe od użytkownika, jego zadaniem jest zapisywanie i przywracanie tych danych w celu obsługi zmian konfiguracji. Wszystkie widoki udostępniane przez platformę Android mają własne implementacje funkcji onSaveInstanceState()
i onRestoreInstanceState()
, więc nie musisz zarządzać stanem widoku w fragmentach.
Na przykład w poprzednim scenariuszu edytowany ciąg znaków jest przechowywany w EditText
. EditText
zna wartość wyświetlanego tekstu, a także inne szczegóły, takie jak początek i koniec dowolnego wybranego tekstu.
Wyświetlanie wymaga identyfikatora, aby zachować stan. Identyfikator musi być niepowtarzalny w ramach fragmentu i jego hierarchii widoków. Widoki bez identyfikatora nie mogą zachować swojego stanu.
<EditText android:id="@+id/good_deed_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" />
Jak wspomnieliśmy w tabeli 1, widoki danych zapisują i przywracają ViewState
za pomocą wszystkich operacji, które nie powodują usunięcia fragmentu ani zniszczenia hosta.
SavedState
Fragment jest odpowiedzialny za zarządzanie niewielkimi ilościami stanu dynamicznego, które są integralną częścią jego działania. Fragment.onSaveInstanceState(Bundle)
pozwala łatwo przechowywać dane w szeregu.
Podobnie jak w przypadku pakietu Activity.onSaveInstanceState(Bundle)
dane umieszczone w bundle’u są zachowywane podczas zmian konfiguracji oraz zatrzymywania i tworzenia procesów. Są one dostępne w metodach onCreate(Bundle)
, onCreateView(LayoutInflater, ViewGroup, Bundle)
i onViewCreated(View, Bundle)
fragmentu.
W przypadku poprzedniego przykładu randomGoodDeed
to akt własności, który jest wyświetlany użytkownikowi, a isEditing
to flaga określająca, czy fragment ma wyświetlać czy ukrywać EditText
. Zapisany stan powinien być utrwalony za pomocą parametru onSaveInstanceState(Bundle)
, jak w tym przykładzie:
Kotlin
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putBoolean(IS_EDITING_KEY, isEditing) outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed) }
Java
@Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(IS_EDITING_KEY, isEditing); outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed); }
Aby przywrócić stan w onCreate(Bundle)
, pobierz zapisaną wartość z paczki:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false) randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY) ?: viewModel.generateRandomGoodDeed() }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false); randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY); } else { randomGoodDeed = viewModel.generateRandomGoodDeed(); } }
Jak wspomnieliśmy w tabeli 1, zmienne są zachowywane, gdy fragment jest umieszczony na stosie backendowym. Gdy traktujesz je jako zapisane, zapewniasz, że nie powodują żadnej destrukcyjnej operacji.
NonConfig
Dane spoza konfiguracji powinny znajdować się poza fragmentem, na przykład w elemencie ViewModel
. W poprzednim przykładzie seed
(stan NonConfig) jest generowany w elementach ViewModel
.
Logika utrzymywania stanu należy do ViewModel
.
Kotlin
public class RandomGoodDeedViewModel : ViewModel() { private val seed = ... // Generate the seed private fun generateRandomGoodDeed(): String { val goodDeed = ... // Generate a random good deed using the seed return goodDeed } }
Java
public class RandomGoodDeedViewModel extends ViewModel { private Long seed = ... // Generate the seed private String generateRandomGoodDeed() { String goodDeed = ... // Generate a random good deed using the seed return goodDeed; } }
Klasa ViewModel
pozwala zachować dane w przypadku zmian konfiguracji, takich jak obracanie ekranu, i pozostają w pamięci, gdy fragment jest umieszczony na stosie. Po zakończeniu procesu i jego ponownym uruchomieniu ViewModel
zostanie utworzona ponownie, a nowy seed
zostanie wygenerowany. Dodanie modułu SavedState
do ViewModel
pozwala ViewModel
zachować prosty stan podczas zabijania i tworzenia procesu.
Dodatkowe materiały
Więcej informacji o zarządzaniu stanem fragmentu znajdziesz w tych dodatkowych materiałach.
Ćwiczenia z programowania
- Ćwiczenie w Codelabs dotyczące komponentów uwzględniających cykl życia