W tej lekcji
Warto przeczytać
- Obsługa różnych ekranów (ang.)
- Obsługa zmian w czasie wykonywania (ang.)
- Przewodnik po aktywnościach (ang.)
Demo
Istnieje kilka sytuacji, w których dochodzi do zniszczenia aktywności w wyniku normalnego funkcjonowania aplikacji, np. po naciśnięciu przez użytkownika przycisku Wstecz, bądź po zasygnalizowaniu przez aktywność końca pracy poprzez metodę finish()
. System może także zniszczyć aktywność, która jest w danej chwili zatrzymana i nie była używana od dłuższego czasu, a także jeśli aktywność uruchomiona na pierwszym planie potrzebuje większych zasobów — aby zwolnić pamięć system musi wówczas zakończyć procesy wykonywane w tle.
Kiedy aktywność zostaje zniszczona w wyniku naciśnięcia przez użytkownika przycisku Wstecz lub jeśli sama zakończy działanie, system trwale usuwa ślad po danej instancji, ponieważ zachowanie programu wskazuje na to, że jest ona zbędna. Jeśli jednak aktywność zostaje zniszczona ze względu na ograniczenia systemowe (a nie w wyniku normalnego funkcjonowania aplikacji), wówczas bieżąca instancja zostaje usunięta, jednak system zapamiętuje, że kiedyś istniała. Jeśli zatem użytkownik wróci do danej aktywności, system utworzy jej nową instancję wykorzystując przy tym zapisane dane na temat jej ostatniego stanu. Dane służące do odzyskania stanu aktywności nazywane są „stanem instancji” i stanowią zbiór par klucz-wartość przechowywany w obiekcie Bundle
.
Domyślnie w stanie instancji z obiektu Bundle
system zapisuje informacje na temat każdego obiektu klasy View
składającego się na układ aplikacji (np. wartości tekstowe wprowadzone do obiektu EditText
). Jeśli dojdzie zatem do zniszczenia i odtworzenia instancji aktywności, system przywróci ostatni stan układu aplikacji bez korzystania z dodatkowego kodu. Może się jednak zdarzyć, że przywracanie całego zapisanego stanu jest zbędne, np. zmiennych składowych dotyczących postępu użytkownika.
Dodatkowe dane dotyczące stanu aktywności zapisuje się poprzez przedefiniowanie metody zwrotnej onSaveInstanceState()
. Jest ona wywołana kiedy użytkownik opuszcza aktywność — jej stan zostaje zapisany w obiekcie Bundle
na wypadek nieoczekiwanego zniszczenia aktywności. Jeśli system będzie musiał później odtworzyć jej egzemplarz, ten sam obiekt Bundle
zostanie przekazany zarówno do metody onRestoreInstanceState()
jak i onCreate()
.
Zapisywanie stanu aktywności
Kiedy następuje zatrzymanie aktywności, system wywołuje metodę onSaveInstanceState()
, aby zapisać dane dotyczące stanu aktywności w zestawie par klucz-warość. W domyślnej implementacji metody zapisane zostają informacje na temat stanu hierarchii widoków, np. tekstu w widżecie EditText
bądź pozycji suwaka w elemencie ListView
.
Aby zapisać dodatkowe informacje na temat stanu aktywności, należy zaimplementować metodę onSaveInstanceState()
i dodać do obiektu Bundle
pary klucz-warość. Przykład:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// zapisz aktualny stan gry użytkownika
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// zawsze wywołuj nadklasę, aby zapisać stan hierarchii widoków
super.onSaveInstanceState(savedInstanceState);
}
Przywracanie stanu aktywności
Jeśli zniszczona aktywność zostanie odtworzona, możesz przywrócić jej stan zapisany w obiekcieBundle
, który jest przekazywany do aktywności przez system. Metody zwrotne onCreate()
i onRestoreInstanceState()
otrzymują ten sam obiekt Bundle
zawierający informacje na temat stanu danego egzemplarza aktywności.
System wywołuje metodę onCreate()
podczas tworzenia nowej instancji aktywności lub odtwarzania wcześniejszego egzemplarza, dlatego przed próbą odczytania obiektu Bundle
musisz sprawdzić, czy jest pusty. W takim wypadku nie będzie próbował przywrócić zniszczonego wystąpienia aktywności, lecz utworzy nowy egzemplarz.
Oto przykład odzyskiwania danych dotyczących stanu poprzez metodę onCreate()
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // zawsze wywołuj metodę z nadklasy jako pierwszą
// sprawdź, czy można odtworzyć zniszczone wcześniej wystąpienie
if (savedInstanceState != null) {
// przywróć wartości składowych z zapisanego stanu
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// prawdopodobnie dla nowej instancji zostaną zainicjowane składowe z wartościami domyślnymi
}
...
}
Oprócz metody onCreate()
do odtworzenia stanu aktywności można zaimplementować metodę onRestoreInstanceState()
, która jest wywoływana przez system po metodzie onStart()
. System wywoła onRestoreInstanceState()
tylko jeśli stan do przywrócenia został wcześniej zapisany. Nie trzeba więc sprawdzać, czy obiekt Bundle
jest pusty:
public void onRestoreInstanceState(Bundle savedInstanceState) {
// zawsze wywołuj metodę z nadklasy, aby można było przywrócić stan hierarchii widoków
super.onRestoreInstanceState(savedInstanceState);
// przywróć składowe stanu z zapisanego egzemplarza
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
Aby dowiedzieć się więcej o odtwarzaniu stanu aktywności w przypadku jej ponownego uruchomienia w czasie wykonywania (np. w wyniku zmiany orientacji ekranu), przeczytaj artykuł Obsługa zmian w czasie wykonywania.