web-dev-qa-db-fra.com

onSaveInstanceState () et onRestoreInstanceState ()

J'essaie de sauvegarder et de restaurer l'état d'une Activity en utilisant les méthodes onSaveInstanceState() et onRestoreInstanceState().

Le problème est qu'il n'entre jamais dans la méthode onRestoreInstanceState(). Quelqu'un peut-il m'expliquer pourquoi c'est?

131
BlaBRA

Habituellement, vous restaurez votre état dans onCreate(). Il est également possible de le restaurer dans onRestoreInstanceState(), mais cela n’est pas très courant. (onRestoreInstanceState() est appelé après onStart(), alors que onCreate() est appelé avant onStart().

Utilisez les méthodes put pour stocker les valeurs dans onSaveInstanceState():

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

Et restaurez les valeurs dans onCreate():

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

Vous n'êtes pas obligé de stocker les états d'affichage, car ils sont stockés automatiquement en appelant super.onSaveInstanceState (icicle) ;.

184
Robert

onRestoreInstanceState() est appelé uniquement lors de la recréation de activité après avoir été tué par le système d'exploitation. Une telle situation se produit lorsque:

  • l'orientation de l'appareil change (votre activité est détruite et recréée)
  • il y a une autre activité devant la vôtre et, à un moment donné, le système d'exploitation tue votre activité pour libérer de la mémoire (par exemple). La prochaine fois que vous commencerez votre activité, onRestoreInstanceState() sera appelé.

En revanche, si vous êtes dans votre activité et que vous appuyez sur le bouton Back de l'appareil, votre activité est terminée () (c'est-à-dire que vous la considérez comme une application de bureau sortante) et la prochaine fois que vous démarrerez votre application, elle sera lancée "fraîche", sans état sauvegardé parce que vous l'avez quitté intentionnellement lorsque vous avez appuyé sur Back.

Une autre source de confusion est que, lorsqu'une application perd le focus sur une autre application, onSaveInstanceState() est appelé mais lorsque vous revenez à votre application, onRestoreInstanceState() peut ne pas être appelé. C’est le cas décrit dans la question initiale, c’est-à-dire si votre activité n’a PAS été arrêtée au cours de la période où une autre activité était antérieure à onRestoreInstanceState() ne sera PAS appelée car votre activité est quasiment "vivante".

Dans l’ensemble, comme indiqué dans la documentation de onRestoreInstanceState():

La plupart des implémentations utiliseront simplement onCreate (Bundle) pour restaurer leur fichier état, mais il est parfois pratique de le faire ici après tout le l’initialisation a été effectuée ou pour permettre aux sous-classes de décider si utiliser votre implémentation par défaut. L'implémentation par défaut de this La méthode effectue une restauration de n’importe quel état de vue qui avait été précédemment gelé par onSaveInstanceState (Bundle).

D'après ce que j'ai lu: Il n'y a aucune raison de remplacer onRestoreInstanceState() à moins de sous-classer Activity et il est prévu que quelqu'un sous-classe votre sous-classe. 

146
Ognyan

L'état que vous enregistrez à onSaveInstanceState() est disponible ultérieurement à l'invocation de la méthode onCreate(). Utilisez donc onCreate (et son paramètre Bundle) pour restaurer l’état de votre activité.

7
Konstantin Burov

Pour contourner le problème, vous pouvez stocker un ensemble contenant les données que vous souhaitez conserver dans l’intention que vous utilisez pour démarrer l’activité A.

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

L'activité A devrait renvoyer cela à l'activité B. Vous récupéreriez l'intention dans la méthode onCreate de l'activité B.

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

Une autre idée consiste à créer une classe de référentiel pour stocker l’état de l’activité et faire en sorte que chacune de vos activités fasse référence à cette classe (possible à l’aide d’une structure singleton). Cependant, cela représente probablement plus de problèmes qu’il ne vaut.

4
sotrh

J'ai trouvé que onSaveInstanceState est toujours appelé lorsqu'une autre activité passe au premier plan. Et il en est de même sur onStop.

Cependant, onRestoreInstanceState a été appelé uniquement lorsque onCreate et onStart ont également été appelés. Et, onCreate et onStart n'étaient PAS toujours appelés.

Il semble donc qu'Android ne supprime pas toujours les informations d'état, même si l'activité passe en arrière-plan. Cependant, il appelle les méthodes de cycle de vie pour enregistrer l'état juste par sécurité. Ainsi, si l'état n'est pas supprimé, Android n'appelle pas les méthodes de cycle de vie pour restaurer l'état car elles ne sont pas nécessaires.

La figure 2 décrit cela.

3
buzz

L'essentiel est que si vous ne stockez pas dans onSaveInstanceState(), alors onRestoreInstanceState() ne sera pas appelé. C'est la principale différence entre restoreInstanceState() et onCreate(). Assurez-vous de stocker vraiment quelque chose. Très probablement, c'est votre problème.

3
user1771286

Je pense que ce fil était assez vieux. Je viens de mentionner un autre cas, que onSaveInstanceState() sera également appelé, est lorsque vous appelez Activity.moveTaskToBack(boolean nonRootActivity)

2
macio.Jun

Si vous gérez les changements d'orientation de l'activité avec Android:configChanges="orientation|screenSize" et onConfigurationChanged(Configuration newConfig), onRestoreInstanceState() ne sera pas appelé.

1
Rajkiran

Il n'est pas nécessaire que onRestoreInstanceState soit toujours appelé après onSaveInstanceState.

Notez que: OnRestoreInstanceState sera toujours appelé lorsque l’activité est tournée (lorsque l’orientation n’est pas gérée) ou ouvre votre activité, puis ouvrez d’autres applications afin que votre instance d’activité soit effacée de la mémoire par le système d’exploitation.

1

Je peux faire comme ça (désolé c'est c # pas Java mais c'est pas un problème ...):

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

ET DANS VOTRE ACTIVITÉ DE RÉSULTAT

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

}

ENFIN

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
base.OnActivityResult (iRequestCode, oResultCode, oIntent);
iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
0
EDynamic90

Je viens juste de le rencontrer et je remarquais que la réponse de ma documentation était la suivante:

"Cette fonction ne sera jamais appelée avec un état nul."

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

Dans mon cas, je me demandais pourquoi onRestoreInstanceState n’était pas appelé lors de l’instanciation initiale. Cela signifie également que si vous ne stockez rien, il ne sera pas appelé lors de la reconstruction de votre vue.

0
Ben Scannell

Dans mon cas, onRestoreInstanceState a été appelé lorsque l'activité a été reconstruite après avoir modifié l'orientation du périphérique. onCreate(Bundle) a été appelé en premier, mais le paquet n'avait pas la clé/les valeurs que j'ai définies avec onSaveInstanceState(Bundle)

Juste après, onRestoreInstanceState(Bundle) a été appelé avec un paquet contenant la clé/les valeurs appropriées.

0
elvitucho