Kiedy dokładnie są wywoływane onSaveInstanceState () i onRestoreInstanceState ()?

102

Poniższy rysunek (z oficjalnego dokumentu ) przedstawia dobrze znany cykl życia działania na Androidzie:

wprowadź opis obrazu tutaj

Z drugiej strony, gdy aktywność zostanie zniszczona przez system (na przykład z powodu konieczności odzyskania pamięci), stan aktywności jest czasami automatycznie zapisywany i przywracany za pomocą metod onSaveInstanceState()i onRestoreInstanceState(), jak pokazano na poniższym rysunku (również z oficjalnego dokumentu ):

wprowadź opis obrazu tutaj

Wiem, że nie zawszeonSaveInstanceState() jest to wywoływane, gdy działanie ma zostać zniszczone. Na przykład, jeśli zostanie zniszczony, ponieważ użytkownik nacisnął przycisk „Wstecz”, stan aktywności nie zostanie zachowany. Ale w przypadkach, gdy stan jest zapisywany i przywracany i onSaveInstanceState()/ gdy onRestoreInstanceState()zostanie wywołany, kiedy dokładnie są wywoływani ?

Na przykład, zgodnie z powyższymi rysunkami, onRestoreInstanceState()może być wywołany przed onStart()lub po, onStart()ale przed onResume()lub po onResume(). Podobnie istnieje kilka możliwości dla onSaveInstanceState(). Kiedy więc są dokładnie nazywani?

W idealnym przypadku chciałbym zobaczyć połączony diagram przedstawiający stany cyklu życia czynności i metody zapisywania / odtwarzania , jeśli takie istnieją.

Luis Mendo
źródło
uzyskał ostateczną odpowiedź z oficjalnego dokumentu Androida, onSaveInstanceState () wywołany między onPause () i onStop ().
Rishi
1
@Rishi Czy możesz podać link do tego dokumentu?
Luis Mendo
przeczytaj Zapisz stan swojej aktywności Paragraf w tym miejscu
Rishi
czy mam rację, czy nie, proszę o wyjaśnienie
Rishi

Odpowiedzi:

107

Zgodnie z dokumentacją :

void onRestoreInstanceState (Pakiet zapisanyInstanceState)

Ta metoda jest wywoływana między onStart()a onPostCreate(Bundle).

void onSaveInstanceState (Bundle outState)

Jeśli zostanie wywołana, ta metoda pojawi się po onStop () dla aplikacji przeznaczonych dla platform zaczynających się od Build.VERSION_CODES.P. W przypadku aplikacji przeznaczonych dla wcześniejszych wersji platformy ta metoda wystąpi przed onStop () i nie ma gwarancji, czy nastąpi to przed, czy po onPause ().

Steve M.
źródło
1
Dzięki. Czy mógłbyś podać linki do dokumentacji?
Luis Mendo
Proszę bardzo, również nie sądzę, by było coś innego między onStart () a onPostCreate (), więc onRestoreInstanceState () jest dobrze zdefiniowany w łańcuchu.
Steve M
Wielkie dzięki. To wyjaśnia problem
Luis Mendo
1
@SteveM "Nie ma gwarancji, że nastąpi to przed, czy po onPause ()" Czy to oznacza, że ​​jeśli spróbujemy uzyskać dostęp do widoku (aby uzyskać jakąś wartość do zapisania, na przykład indeks z widoku listy), możemy napotkać NullPointerExceptions?
Tiago
3
Następnie, co jest zalecane, aby zapisać strukturę danych w onPause i przywrócić ją w onResume zamiast w onSaveInstanceState i onRestoreInstanceState?
Gödel77
18

Zgodnie z doc1 i doc2

onSaveInstanceState

Przed Honeycomb działania były uznawane za możliwe do zabicia dopiero po ich wstrzymaniu, co oznacza, że ​​onSaveInstanceState () była wywoływana bezpośrednio przed onPause (). Jednak począwszy od Honeycomb, Działania są uznawane za możliwe do zabicia dopiero po ich zatrzymaniu, co oznacza, że ​​onSaveInstanceState () będzie teraz wywoływane przed onStop () zamiast bezpośrednio przed onPause ().

onRestoreInstanceState

Ta metoda jest wywoływana między onStart () i onPostCreate (Bundle), gdy działanie jest ponownie inicjowane z wcześniej zapisanego stanu

Programista Androida
źródło
podobał mi się sposób, w jaki opisałeś scenariusze w różnych wersjach Androida
Jimit Patel,
14

Oprócz opublikowanych już odpowiedzi, w Androidzie P wprowadzono subtelną zmianę, która jest:

void onSaveInstanceState (Bundle outState)

Jeśli wywołana metoda ta nastąpi PO onStop() dla aplikacji atakujących platformy zaczynające P . W przypadku aplikacji przeznaczonych dla wcześniejszych wersji platformy ta metoda zostanie zastosowana przed onStop()i nie ma gwarancji, czy nastąpi to przed, czy po onPause().

Źródło: docs

Oto odpowiedź na pytanie, dlaczego wprowadzono tę zmianę:

... dzięki czemu aplikacja może bezpiecznie wykonywać transakcje fragmentaryczne w onStop()i będzie mogła później zachować trwały stan.

Źródło: docs

azizbekian
źródło
Cześć, świetny komentarz. Czy wiesz, jak zachowa się aplikacja ukierunkowana na P, ale działa na niższym api? To samo, co kierowanie aplikacji na niższy interfejs API, czy też będzie spójne w całym interfejsie API i zachowa zachowanie „docelowego interfejsu API”?
Filipkowicz
@Filipkowicz, Do you know how will behave app that target P but runs on lower api?Dopóki aplikacja działa na powiedzmy M, to wersja Androida, którą to urządzenie ma, nie zawiera zmian, które są wprowadzane w P, co oznacza, że ​​niezależnie od wskazanego celu P, nie zobaczysz inny dla urządzeń pre-P. Mam nadzieję, że to odpowiada na twoje pytanie.
azizbekian
Po przeczytaniu tej odpowiedzi czuję się dziś bardzo zrelaksowany, ponieważ robiłem darmowy kurs na Androida na temat Udacity, a oni nadal mają starą wersję samouczków, które w lekcji 5, ćwiczenie 8 stwierdzają, że metody onStop i onDestroy nie powinny być dostępne w wyświetlany textView. Ale nie wiedziałem, że dotyczy to starszych wersji Androida i uruchomiłem moją aplikację na Android Pie i otrzymywałem metodę onStop w moim textView. Dziękuję bardzo. Wreszcie czuję się dobrze.
Sandhu
6

To jest dodatkowa informacja dla onSaveInstanceState (pakiet)

z dokumentów

Nie należy mylić tej metody z wywołaniami zwrotnymi cyklu życia działania, takimi jak onPause (), które są zawsze wywoływane, gdy działanie jest umieszczane w tle lub w drodze do zniszczenia, lub onStop (), które jest wywoływane przed zniszczeniem. Jednym z przykładów wywołania onPause () i onStop (), a nie tej metody, jest sytuacja, gdy użytkownik przechodzi z powrotem z działania B do działania A: nie ma potrzeby wywoływania onSaveInstanceState (Bundle) na B, ponieważ ta konkretna instancja nigdy nie zostanie przywrócona , więc system unika wywoływania go. Przykładem wywołania onPause (), a nie onSaveInstanceState (Bundle), jest sytuacja, w której działanie B jest uruchamiane przed działaniem A: system może uniknąć wywołania onSaveInstanceState (Bundle) w działaniu A, jeśli nie zostanie ono zabite w okresie życia B, ponieważ stan interfejsu użytkownika A pozostanie nienaruszony.

Jest to więc domyślna implementacja ...

Domyślna implementacja zajmuje się większością stanu interfejsu użytkownika dla każdej instancji, wywołując metodę onSaveInstanceState () w każdym widoku w hierarchii, który ma identyfikator, i zapisując identyfikator aktualnie aktywnego widoku (z których wszystkie są przywracane przez domyślna implementacja onRestoreInstanceState (Bundle)). Jeśli zastąpisz tę metodę, aby zapisać dodatkowe informacje, które nie zostały przechwycone przez poszczególne widoki, prawdopodobnie będziesz chciał wywołać domyślną implementację, w przeciwnym razie przygotuj się na samodzielne zapisanie całego stanu każdego widoku.

Mahmoud Mzz
źródło
0
String activityState;
@Override 
public void onCreate(Bundle savedInstanceState) {
// call the super class onCreate to complete the creation of activity like 
// the view hierarchy 
super.onCreate(savedInstanceState);

// recovering the instance state 
if (savedInstanceState != null) {
     activityState = savedInstanceState.getString(STATE_KEY);
 } 

   setContentView(R.layout.main_activity);
   mTextView = (TextView) findViewById(R.id.text_view);
} 

// To wywołanie zwrotne jest wywoływane tylko wtedy, gdy istnieje zapisana instancja, która została wcześniej zapisana przy użyciu // onSaveInstanceState (). Przywracamy pewien stan w onCreate (), podczas gdy możemy opcjonalnie przywrócić // inny stan tutaj, prawdopodobnie nadający się do użytku po zakończeniu onStart (). // Pakiet saveInstanceState jest taki sam, jak ten użyty w onCreate ().

@Override 
public void onRestoreInstanceState(Bundle savedInstanceState) {
 mTextView.setText(savedInstanceState.getString(STATE_KEY));
  } 


// invoked when the activity may be temporarily destroyed, save the instance 
//state here 
//this method will be called before onstop

@Override 
 public void onSaveInstanceState(Bundle outState) {
    outState.putString(STATE_KEY, activityState);

    // call superclass to save any view hierarchy 
    super.onSaveInstanceState(outState);
} 
parvez rafi
źródło
Przepraszam, jak to odpowiada na pytanie, kiedy dokładnie wywoływane są metody składowania / odtwarzania ?
Luis Mendo