onSaveInstanceState () e onRestoreInstanceState ()


138

Sto cercando di salvare e ripristinare lo stato di un Activityusando i metodi onSaveInstanceState()e onRestoreInstanceState().

Il problema è che non entra mai nel onRestoreInstanceState()metodo. Qualcuno può spiegarmi perché questo è?


1
@Nitin: grazie per aver condiviso il link ... questo mi ha chiarito alcune cose +1
Taliadon

2
@NitinBansal il link è morto.
ashishdhiman2007,

Risposte:


191

Di solito ripristini il tuo stato in onCreate(). È possibile ripristinarlo anche in onRestoreInstanceState(), ma non molto comune. ( onRestoreInstanceState()viene chiamato dopo onStart(), mentre onCreate()viene chiamato prima onStart().

Utilizzare i metodi messi a memorizzare i valori di onSaveInstanceState():

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

E ripristina i valori in onCreate():

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

2
il problema è che uso startActivity per tornare all'attività A. Quando torno all'attività B, l'oggetto è ghiacciolo nullo.
BlaBRA,

5
Se ho capito bene, questo è quello che stai facendo: da B chiami startActivity (A). Quindi da A chiami finish () per tornare a B. Giusto? In tal caso, la tua prima attività, B non sarà stata distrutta e né onCreate () né onRestoreInstanceState () verranno chiamati. Questi metodi vengono chiamati solo quando necessario, ovvero quando un'attività è stata distrutta e deve essere ricreata dal sistema.
Robert,

4
Dovrei aggiungere che la tua prima attività, B, potrebbe essere distrutta a causa delle condizioni di memoria insufficiente. Ciò attiverà onCreate e onRestoreInstanceState.
Robert,

1
erikb, sì, l'attività B verrà ripresa, o nel caso in cui il sistema operativo l'abbia recuperata, ricreata e quindi ripresa.
Robert,


149

onRestoreInstanceState()viene chiamato solo quando si ricrea attività dopo che è stato ucciso dal sistema operativo. Tale situazione si verifica quando:

  • l'orientamento del dispositivo cambia (l'attività viene distrutta e ricreata).
  • c'è un'altra attività davanti alla tua e ad un certo punto il sistema operativo uccide la tua attività per liberare memoria (ad esempio). La prossima volta che avvierai la tua attività onRestoreInstanceState () verrà chiamato.

Al contrario: se sei nella tua attività e premi il Backpulsante sul dispositivo, la tua attività è terminata () ed (ovvero pensala come uscita dall'applicazione desktop) e la prossima volta che avvii l'app viene avviata "nuova", cioè senza stato salvato perché lo hai lasciato intenzionalmente quando hai colpito Back.

Un'altra fonte di confusione è che quando un'app perde il focus su un'altra app onSaveInstanceState()viene chiamata ma quando si ritorna all'app onRestoreInstanceState()non può essere chiamata. Questo è il caso descritto nella domanda originale, vale a dire se la tua attività NON è stata uccisa durante il periodo in cui un'altra attività era davanti onRestoreInstanceState()NON verrà chiamata perché la tua attività è praticamente "viva".

Tutto sommato, come indicato nella documentazione per onRestoreInstanceState():

La maggior parte delle implementazioni utilizzerà semplicemente onCreate (Bundle) per ripristinare il proprio stato, ma a volte è conveniente farlo qui dopo che è stata eseguita tutta l'inizializzazione o per consentire alle sottoclassi di decidere se utilizzare l'implementazione predefinita. L'implementazione predefinita di questo metodo esegue un ripristino di qualsiasi stato di visualizzazione precedentemente bloccato da onSaveInstanceState (Bundle).

Mentre lo leggo: non c'è motivo di eseguire l'override a onRestoreInstanceState()meno che non si stia effettuando una sottoclasse Activitye si prevede che qualcuno effettuerà una sottoclasse della sottoclasse.


3
Sì, questo sembra essere giusto, ma fa schifo. imo dovrebbe essere eseguito anche quando si ritorna all'attività da un'altra attività. ci sono molte situazioni in cui ne hai bisogno.
masi,

4
@masi ci sono già altri metodi invocati su Activity quando l'utente vi ritorna (da un'altra attività). OnSave / RestoreInstanceState () viene utilizzato per un altro scopo specifico, tutto qui.
Superjos

8

Lo stato in cui si salva onSaveInstanceState()è successivamente disponibile al onCreate()richiamo del metodo. Quindi usa onCreate(e il suo Bundleparametro) per ripristinare lo stato della tua attività.


4

Per ovviare al problema, è possibile archiviare un pacchetto con i dati che si desidera conservare nell'intento che si utilizza per avviare l'attività A.

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

L'attività A dovrebbe restituirla all'attività B. Si recupererebbe l'intento nel metodo onCreate dell'attività B.

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

Un'altra idea è quella di creare una classe di repository per memorizzare lo stato delle attività e fare in modo che ciascuna delle tue attività faccia riferimento a quella classe (possibile utilizzando una struttura singleton). Tuttavia, farlo probabilmente è più un problema di quanto valga la pena.


3

La cosa principale è che se non si memorizzano in onSaveInstanceState()poi onRestoreInstanceState()non sarà chiamato. Questa è la differenza principale tra restoreInstanceState()e onCreate(). Assicurati di conservare davvero qualcosa. Molto probabilmente questo è il tuo problema.


1
onRestoreInstanceState () verrà chiamato, anche se non memorizzi nulla in OnSaveInstanceState ()
abh22ishek,

3

Ho scoperto che onSaveInstanceState viene sempre chiamato quando viene visualizzata un'altra attività in primo piano. E così è onStop.

Tuttavia, onRestoreInstanceState è stato chiamato solo quando sono stati chiamati anche onCreate e onStart. E onCreate e onStart NON venivano sempre chiamati.

Quindi sembra che Android non elimini sempre le informazioni sullo stato anche se l'attività si sposta in background. Tuttavia, chiama i metodi del ciclo di vita per salvare lo stato solo per sicurezza. Pertanto, se lo stato non viene eliminato, Android non chiama i metodi del ciclo di vita per ripristinare lo stato in quanto non sono necessari.

La Figura 2 descrive questo.


2

Penso che questo thread fosse piuttosto vecchio. Ho appena citato un altro caso, che onSaveInstanceState()verrà anche chiamato, è quando chiami Activity.moveTaskToBack(boolean nonRootActivity).


1

Se si gestiscono le modifiche all'orientamento dell'attività con android:configChanges="orientation|screenSize"e onConfigurationChanged(Configuration newConfig), onRestoreInstanceState()non verranno chiamate.


1

Non è necessario che onRestoreInstanceState venga sempre chiamato dopo onSaveInstanceState.

Nota che: onRestoreInstanceState verrà sempre chiamato, quando l'attività viene ruotata (quando l'orientamento non viene gestito) o apri l'attività e quindi apri altre app in modo che l'istanza dell'attività venga cancellata dalla memoria dal sistema operativo.


1

Dalla documentazione Ripristinare lo stato dell'interfaccia utente dell'attività utilizzando lo stato dell'istanza salvato è indicato come:

Invece di ripristinare lo stato durante onCreate () è possibile scegliere di implementare onRestoreInstanceState (), che il sistema chiama dopo il metodo onStart (). Il sistema chiama onRestoreInstanceState () solo se è presente uno stato salvato da ripristinare, quindi non è necessario verificare se il pacchetto è null :

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

IMO, questo è un modo più chiaro che controllarlo su onCreate e si adatta meglio al principio della singola responsabilità.


0

Nel mio caso, è onRestoreInstanceStatestato chiamato quando l'attività è stata ricostruita dopo aver modificato l'orientamento del dispositivo. onCreate(Bundle)è stato chiamato per primo, ma il bundle non aveva la chiave / i valori con cui ho impostato onSaveInstanceState(Bundle).

Subito dopo, è onRestoreInstanceState(Bundle)stato chiamato con un bundle che aveva la chiave / i valori corretti.



0

Posso fare così (scusate se non c # java ma non è un problema ...):

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

E NELLA TUA ATTIVITÀ PER IL RISULTATO

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

FINALMENTE

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.