Próbuję zapisać i przywrócić stan pliku Activity
przy użyciu metod onSaveInstanceState()
i onRestoreInstanceState()
.
Problem w tym, że nigdy nie wchodzi do onRestoreInstanceState()
metody. Czy ktoś może mi wyjaśnić, dlaczego tak jest?
Próbuję zapisać i przywrócić stan pliku Activity
przy użyciu metod onSaveInstanceState()
i onRestoreInstanceState()
.
Problem w tym, że nigdy nie wchodzi do onRestoreInstanceState()
metody. Czy ktoś może mi wyjaśnić, dlaczego tak jest?
Odpowiedzi:
Zwykle przywracasz swój stan w onCreate()
. Można go onRestoreInstanceState()
również przywrócić , ale niezbyt często. ( onRestoreInstanceState()
nazywa się po onStart()
, a onCreate()
nazywa się przed onStart()
.
Użyj metod put do przechowywania wartości w onSaveInstanceState()
:
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
icicle.putLong("param", value);
}
I przywróć wartości w onCreate()
:
public void onCreate(Bundle icicle) {
if (icicle != null){
value = icicle.getLong("param");
}
}
onRestoreInstanceState()
jest wywoływana tylko podczas odtwarzania aktywności po jej zabiciu przez system operacyjny. Taka sytuacja ma miejsce, gdy:
W przeciwieństwie do tego: jeśli jesteś w swojej aktywności i naciśniesz Back
przycisk na urządzeniu, Twoja aktywność zostanie zakończona () ed (tj. Pomyśl o tym jak o wyjściu z aplikacji komputerowej) i następnym razem, gdy uruchomisz aplikację, zostanie uruchomiona „od nowa”, tj. Bez zapisany stan, ponieważ celowo opuściłeś go po uderzeniu Back
.
Innym źródłem nieporozumień jest to, że gdy aplikacja traci fokus na inną aplikację, onSaveInstanceState()
jest wywoływana, ale po powrocie do aplikacji onRestoreInstanceState()
może nie zostać wywołana. Tak jest w przypadku opisanym w pierwotnym pytaniu, tj. Jeśli twoja czynność NIE została zabita w okresie, gdy inna czynność była z przodu onRestoreInstanceState()
, NIE zostanie wywołana, ponieważ twoja aktywność jest prawie „żywa”.
Podsumowując, jak podano w dokumentacji onRestoreInstanceState()
:
Większość implementacji użyje po prostu onCreate (Bundle) do przywrócenia ich stanu, ale czasami wygodnie jest to zrobić tutaj po wykonaniu całej inicjalizacji lub pozwolić podklasom zdecydować, czy użyć domyślnej implementacji. Domyślna implementacja tej metody wykonuje przywracanie dowolnego stanu widoku, który został wcześniej zamrożony przez onSaveInstanceState (Bundle).
Tak jak to przeczytałem: nie ma powodu do nadpisywania, onRestoreInstanceState()
chyba że tworzysz podklasę Activity
i oczekuje się, że ktoś podklasuje twoją podklasę.
Stan, w którym zapisujesz, onSaveInstanceState()
jest później dostępny podczas onCreate()
wywołania metody. Dlatego użyj onCreate
(i jego Bundle
parametru), aby przywrócić stan swojej aktywności.
Aby obejść ten problem, możesz przechowywać pakiet z danymi, które chcesz zachować, w zamiarze, którego używasz do rozpoczęcia działania A.
Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("bundle", theBundledData);
startActivity(intent);
Działanie A musiałoby przekazać to z powrotem do działania B. Możesz pobrać intencję w metodzie onCreate działania B.
Intent intent = getIntent();
Bundle intentBundle;
if (intent != null)
intentBundle = intent.getBundleExtra("bundle");
// Do something with the data.
Innym pomysłem jest utworzenie klasy repozytorium do przechowywania stanu aktywności i umieszczenie każdego z twoich działań w odniesieniu do tej klasy (możliwe przy użyciu struktury singleton). Jednak zrobienie tego prawdopodobnie jest bardziej kłopotliwe niż warte.
Najważniejsze jest to, że jeśli nie przechowywać w onSaveInstanceState()
czym onRestoreInstanceState()
nie zostanie wywołana. To jest główna różnica między restoreInstanceState()
i onCreate()
. Upewnij się, że naprawdę coś przechowujesz. Najprawdopodobniej to twój problem.
Zauważyłem, że onSaveInstanceState jest zawsze wywoływana, gdy na pierwszym planie pojawia się inne działanie. I tak jest onStop.
Jednak onRestoreInstanceState została wywołana tylko wtedy, gdy wywołano również onCreate i onStart. A onCreate i onStart NIE zawsze były wywoływane.
Wygląda więc na to, że Android nie zawsze usuwa informacje o stanie, nawet jeśli działanie jest przenoszone w tle. Jednak wywołuje metody cyklu życia, aby zapisać stan tylko dla bezpieczeństwa. Dlatego jeśli stan nie zostanie usunięty, system Android nie wywoła metod cyklu życia w celu przywrócenia stanu, ponieważ nie są one potrzebne.
Rysunek 2 to opisuje.
Nie jest konieczne, aby onRestoreInstanceState zawsze był wywoływany po onSaveInstanceState.
Zwróć uwagę, że: onRestoreInstanceState będzie zawsze wywoływane, gdy aktywność zostanie obrócona (gdy orientacja nie jest obsługiwana) lub otworzy Twoją aktywność, a następnie otwórz inne aplikacje, aby instancja aktywności została wyczyszczona z pamięci przez system operacyjny.
Z dokumentacji Przywróć stan interfejsu użytkownika aktywności przy użyciu zapisanego stanu instancji jest to:
Zamiast przywracać stan podczas onCreate (), możesz wybrać implementację onRestoreInstanceState (), którą system wywołuje po metodzie onStart (). System wywołuje metodę onRestoreInstanceState () tylko wtedy, gdy istnieje zapisany stan do przywrócenia, więc nie ma potrzeby sprawdzania, czy pakiet jest pusty :
IMO, to jest bardziej przejrzysty sposób niż sprawdzanie tego w onCreate i lepiej pasuje do zasady pojedynczej odpowiedzialności.
W moim przypadku onRestoreInstanceState
został wywołany, gdy czynność została zrekonstruowana po zmianie orientacji urządzenia. onCreate(Bundle)
został wywołany jako pierwszy, ale pakiet nie miał klucza / wartości, który ustawiłemonSaveInstanceState(Bundle)
.
Zaraz potem onRestoreInstanceState(Bundle)
został wywołany z pakietem, który miał poprawne klucze / wartości.
Właśnie wpadłem na to i zauważyłem, że dokumentacja zawiera moją odpowiedź:
„Ta funkcja nigdy nie zostanie wywołana ze stanem zerowym”.
W moim przypadku zastanawiałem się, dlaczego onRestoreInstanceState nie jest wywoływany podczas początkowej instancji. Oznacza to również, że jeśli nic nie zapiszesz, nie zostanie to wywołane, gdy przejdziesz do rekonstrukcji widoku.
Mogę to zrobić (przepraszam, że to nie java, ale to nie jest problem ...):
private int iValue = 1234567890;
function void MyTest()
{
Intent oIntent = new Intent (this, typeof(Camera2Activity));
Bundle oBundle = new Bundle();
oBundle.PutInt("MYVALUE", iValue); //=> 1234567890
oIntent.PutExtras (oBundle);
iRequestCode = 1111;
StartActivityForResult (oIntent, 1111);
}
I W TWOJEJ DZIAŁALNOŚCI DLA REZULTATU
private int iValue = 0;
protected override void OnCreate(Bundle bundle)
{
Bundle oBundle = Intent.Extras;
if (oBundle != null)
{
iValue = oBundle.GetInt("MYVALUE", 0);
//=>1234567890
}
}
private void FinishActivity(bool bResult)
{
Intent oIntent = new Intent();
Bundle oBundle = new Bundle();
oBundle.PutInt("MYVALUE", iValue);//=>1234567890
oIntent.PutExtras(oBundle);
if (bResult)
{
SetResult (Result.Ok, oIntent);
}
else
SetResult(Result.Canceled, oIntent);
GC.Collect();
Finish();
}
WRESZCIE
protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
base.OnActivityResult (iRequestCode, oResultCode, oIntent);
iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}