onSaveInstanceState () und onRestoreInstanceState ()


138

Ich versuche, den Status eines Activitymit den Methoden onSaveInstanceState()und zu speichern und wiederherzustellen onRestoreInstanceState().

Das Problem ist, dass es nie in die onRestoreInstanceState()Methode eingeht . Kann mir jemand erklären, warum das so ist?


1
@ Nitin: Danke für das Teilen des Links ... dies hat ein paar Dinge für mich
geklärt

2
@NitinBansal der Link ist tot.
ashishdhiman2007

Antworten:


190

Normalerweise stellen Sie Ihren Zustand in wieder her onCreate(). Es ist möglich, es auch wiederherzustellen onRestoreInstanceState(), aber nicht sehr häufig. ( onRestoreInstanceState()wird nachher aufgerufen onStart(), während onCreate()vorher aufgerufen wird onStart().

Verwenden Sie die put-Methoden, um Werte zu speichern in onSaveInstanceState():

protected void onSaveInstanceState(Bundle icicle) {
  super.onSaveInstanceState(icicle);
  icicle.putLong("param", value);
}

Und stellen Sie die Werte wieder her in onCreate():

public void onCreate(Bundle icicle) {
  if (icicle != null){
    value = icicle.getLong("param");
  }
}

2
Das Problem ist, dass ich startActivity verwende, um zu Aktivität A zurückzukehren. Wenn ich zu Aktivität B zurückkehre, ist das Objekt null Eiszapfen.
BlaBRA

5
Wenn ich das richtig verstehe, tun Sie Folgendes: Von B aus rufen Sie startActivity (A) auf. Dann rufen Sie von A aus finish () auf, um zu B zurückzukehren. Richtig? In diesem Fall wurde Ihre erste Aktivität B nicht zerstört, und weder onCreate () noch onRestoreInstanceState () werden aufgerufen. Diese Methoden werden nur bei Bedarf aufgerufen, dh wenn eine Aktivität zerstört wurde und vom System neu erstellt werden muss.
Robert

4
Ich sollte hinzufügen, dass Ihre erste Aktivität, B, aufgrund geringer Speicherbedingungen zerstört werden könnte. Dies löst den onCreate und onRestoreInstanceState aus.
Robert

1
erikb, ja, Aktivität B wird fortgesetzt, oder falls das Betriebssystem sie zurückgefordert hat, neu erstellt und dann wieder aufgenommen.
Robert


149

onRestoreInstanceState()genannt wird , nur dann , wenn neu erstellt Aktivität , nachdem sie wurde getötet durch das Betriebssystem. Eine solche Situation tritt auf, wenn:

  • Die Ausrichtung des Geräts ändert sich (Ihre Aktivität wird zerstört und neu erstellt).
  • Vor Ihnen liegt eine weitere Aktivität, und irgendwann beendet das Betriebssystem Ihre Aktivität, um beispielsweise Speicherplatz freizugeben. Wenn Sie das nächste Mal Ihre Aktivität starten, wird onRestoreInstanceState () aufgerufen.

Im Gegensatz dazu: Wenn Sie sich in Ihrer Aktivität befinden und die BackTaste auf dem Gerät drücken, wird Ihre Aktivität beendet () (dh als beenden Sie die Desktop-Anwendung) und beim nächsten Start Ihrer App wird sie "frisch" gestartet, dh ohne gespeicherter Zustand, weil Sie ihn absichtlich verlassen haben, als Sie getroffen haben Back.

Eine andere Quelle der Verwirrung ist, dass wenn eine App den Fokus auf eine andere App verliert, diese onSaveInstanceState()aufgerufen wird, wenn Sie jedoch zurück zu Ihrer App navigieren, diese onRestoreInstanceState()möglicherweise nicht aufgerufen wird. Dies ist der in der ursprünglichen Frage beschriebene Fall, dh wenn Ihre Aktivität während des Zeitraums, in dem andere Aktivitäten im onRestoreInstanceState()Vordergrund standen, NICHT getötet wurde, wird sie NICHT aufgerufen, da Ihre Aktivität so ziemlich "lebendig" ist.

Alles in allem, wie in der Dokumentation angegeben für onRestoreInstanceState():

Die meisten Implementierungen verwenden einfach onCreate (Bundle), um ihren Status wiederherzustellen. Manchmal ist es jedoch zweckmäßig, dies nach Abschluss der Initialisierung hier zu tun oder Unterklassen die Möglichkeit zu geben, zu entscheiden, ob Ihre Standardimplementierung verwendet werden soll. Die Standardimplementierung dieser Methode führt eine Wiederherstellung aller Ansichtsstatus durch, die zuvor von onSaveInstanceState (Bundle) eingefroren wurden.

Wie ich es gelesen habe: Es gibt keinen Grund zum Überschreiben, es onRestoreInstanceState()sei denn, Sie sind eine Unterklasse Activityund es wird erwartet, dass jemand Ihre Unterklasse unterordnet.


3
yeh das scheint richtig zu sein, aber es ist scheiße. Imo sollte es auch ausgeführt werden, wenn Sie von einer anderen Aktivität zur Aktivität zurückkehren. Es gibt viele Situationen, in denen Sie dies benötigen.
Masi

4
@masi Es gibt bereits andere Methoden, die für Aktivität aufgerufen werden, wenn der Benutzer zu dieser zurückkehrt (von einer anderen Aktivität). OnSave / RestoreInstanceState () wird für einen anderen bestimmten Zweck verwendet, das war's.
Superjos

8

Der Status, in dem Sie speichern, onSaveInstanceState()ist später beim onCreate()Methodenaufruf verfügbar . Verwenden Sie also onCreate(und seinen BundleParameter), um den Status Ihrer Aktivität wiederherzustellen.


4

Um dieses Problem zu umgehen, können Sie ein Bundle mit den Daten, die Sie verwalten möchten, in der Absicht speichern, mit der Sie Aktivität A starten.

Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("bundle", theBundledData);
startActivity(intent);

Aktivität A müsste dies an Aktivität B zurückgeben. Sie würden die Absicht in der onCreate-Methode von Aktivität B abrufen.

Intent intent = getIntent();
Bundle intentBundle;
if (intent != null)
    intentBundle = intent.getBundleExtra("bundle");
// Do something with the data.

Eine andere Idee besteht darin, eine Repository-Klasse zu erstellen, um den Aktivitätsstatus zu speichern und jede Ihrer Aktivitäten auf diese Klasse verweisen zu lassen (möglich mithilfe einer Singleton-Struktur). Dies ist jedoch wahrscheinlich schwieriger als es wert ist.


3

Die Hauptsache ist, dass, wenn Sie nicht in speichern, onSaveInstanceState()dann onRestoreInstanceState()nicht aufgerufen wird. Dies ist der Hauptunterschied zwischen restoreInstanceState()und onCreate(). Stellen Sie sicher, dass Sie wirklich etwas aufbewahren. Höchstwahrscheinlich ist dies Ihr Problem.


1
onRestoreInstanceState () wird aufgerufen, auch wenn Sie nichts in OnSaveInstanceState () speichern
abh22ishek

3

Ich habe festgestellt, dass onSaveInstanceState immer aufgerufen wird, wenn eine andere Aktivität in den Vordergrund tritt. Und so ist onStop.

OnRestoreInstanceState wurde jedoch nur aufgerufen, wenn auch onCreate und onStart aufgerufen wurden. Und onCreate und onStart wurden NICHT immer aufgerufen.

Es scheint also, dass Android die Statusinformationen nicht immer löscht, selbst wenn die Aktivität in den Hintergrund tritt. Es werden jedoch die Lebenszyklusmethoden aufgerufen, um den Status zu speichern, um die Sicherheit zu gewährleisten. Wenn der Status nicht gelöscht wird, ruft Android die Lebenszyklusmethoden nicht auf, um den Status wiederherzustellen, da sie nicht benötigt werden.

Abbildung 2 beschreibt dies.


2

Ich denke, dieser Thread war ziemlich alt. Ich erwähne nur einen anderen Fall, der onSaveInstanceState()auch genannt wird, wenn Sie anrufen Activity.moveTaskToBack(boolean nonRootActivity).


1

Wenn Sie die Ausrichtung der Aktivität mit android:configChanges="orientation|screenSize"und ändern onConfigurationChanged(Configuration newConfig), onRestoreInstanceState()wird sie nicht aufgerufen.


1

Es ist nicht erforderlich, dass onRestoreInstanceState immer nach onSaveInstanceState aufgerufen wird.

Beachten Sie Folgendes: onRestoreInstanceState wird immer aufgerufen, wenn die Aktivität gedreht wird (wenn die Ausrichtung nicht berücksichtigt wird) oder wenn Sie Ihre Aktivität öffnen und dann andere Apps öffnen, damit Ihre Aktivitätsinstanz vom Betriebssystem aus dem Speicher gelöscht wird.


1

In der Dokumentation wird der Status der Aktivitäts-Benutzeroberfläche mithilfe des Status der gespeicherten Instanz wiederhergestellt wie folgt angegeben:

Anstatt den Status während onCreate () wiederherzustellen, können Sie onRestoreInstanceState () implementieren, das das System nach der onStart () -Methode aufruft. Das System ruft onRestoreInstanceState () nur auf, wenn ein gespeicherter Status wiederhergestellt werden muss. Sie müssen also nicht überprüfen, ob das Bundle null ist :

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

IMO, dies ist klarer als die Überprüfung bei onCreate und passt besser zum Prinzip der Einzelverantwortung.


0

In meinem Fall onRestoreInstanceStatewurde aufgerufen, als die Aktivität nach Änderung der Geräteorientierung rekonstruiert wurde. onCreate(Bundle)wurde zuerst aufgerufen, aber das Bundle hatte nicht die Schlüssel / Werte, mit denen ich festgelegt habe onSaveInstanceState(Bundle).

Gleich danach onRestoreInstanceState(Bundle)wurde mit einem Bundle aufgerufen, das die richtigen Schlüssel / Werte hatte.


0

Ich bin gerade darauf gestoßen und habe bemerkt, dass die Dokumentation meine Antwort hatte:

"Diese Funktion wird niemals mit einem Nullzustand aufgerufen."

https://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)

In meinem Fall habe ich mich gefragt, warum der onRestoreInstanceState bei der ersten Instanziierung nicht aufgerufen wurde. Dies bedeutet auch, dass wenn Sie nichts speichern, es nicht aufgerufen wird, wenn Sie Ihre Ansicht rekonstruieren.


0

Ich kann das so machen (sorry, es ist c # nicht Java, aber es ist kein 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);
}

UND IN IHRER AKTIVITÄT FÜR ERGEBNISSE

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();
}

ENDLICH

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.