Sto cercando di salvare e ripristinare lo stato di un Activity
usando i metodi onSaveInstanceState()
e onRestoreInstanceState()
.
Il problema è che non entra mai nel onRestoreInstanceState()
metodo. Qualcuno può spiegarmi perché questo è?
Sto cercando di salvare e ripristinare lo stato di un Activity
usando i metodi onSaveInstanceState()
e onRestoreInstanceState()
.
Il problema è che non entra mai nel onRestoreInstanceState()
metodo. Qualcuno può spiegarmi perché questo è?
Risposte:
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");
}
}
onRestoreInstanceState()
viene chiamato solo quando si ricrea attività dopo che è stato ucciso dal sistema operativo. Tale situazione si verifica quando:
Al contrario: se sei nella tua attività e premi il Back
pulsante 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 Activity
e si prevede che qualcuno effettuerà una sottoclasse della sottoclasse.
Lo stato in cui si salva onSaveInstanceState()
è successivamente disponibile al onCreate()
richiamo del metodo. Quindi usa onCreate
(e il suo Bundle
parametro) per ripristinare lo stato della tua attività.
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.
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.
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.
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.
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 :
IMO, questo è un modo più chiaro che controllarlo su onCreate e si adatta meglio al principio della singola responsabilità.
Nel mio caso, è onRestoreInstanceState
stato 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.
Mi sono appena imbattuto in questo e ho notato che la documentazione aveva la mia risposta:
"Questa funzione non verrà mai chiamata con uno stato null."
Nel mio caso, mi chiedevo perché onRestoreInstanceState non venisse chiamato alla prima istanza. Questo significa anche che se non memorizzi nulla, non verrà chiamato quando vai a ricostruire la tua vista.
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
}