82 votes

savedInstanceState est toujours nul

Voici mon code savedInstaceState :

@Override
public void onSaveInstanceState(Bundle savedInstanceState) 
{
    savedInstanceState.putStringArrayList("todo_arraylist", Altodo);
    Log.v("bundle", "Saved");
    super.onSaveInstanceState(savedInstanceState);
}

public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) 
    {
        Altodo = savedInstanceState.getStringArrayList("todo_arraylist");
        Log.v("bundle", "Restored");
    }
    else
    {
        Log.v("bundle", "null");
    }

    setContentView(R.layout.main);
}

Les journaux montrent toujours la balise "bundle save".

Mais en onCreate méthode, SavedInstanceState est toujours nul.

2 votes

Vous devez appeler super.onSaveInstanceState(savedInstanceState) avant d'ajouter vos valeurs au Bundle, sinon elles seront effacées lors de cet appel (Droid X Android 2.2).

2 votes

J'ai le même problème et je peux confirmer que cela ne fonctionne pas. Quelqu'un l'a déjà résolu ?

57voto

s.bandara Points 5551

J'ai observé exactement les mêmes symptômes (signalés comme numéro 133394 ) dans un projet comportant deux activités A y B qui s'étendent ActionBarActivity . Activité A est l'activité principale, et je reçois toujours null pour savedInstanceState en onCreate de son fragment de liste lors du retour d'une activité de vue détaillée B . Après plusieurs heures, ce problème s'est révélé être un problème de navigation déguisé.

Ce qui suit peut être pertinent pour mon installation et provient d'autres réponses sur cette page :

  • Étant donné que este j'ai fait en sorte que le fragment et l'activité aient chacun un identifiant unique.
  • Il n'y a pas de remplacement de onSaveInstanceState sans super appeler.
  • Activité A est spécifié comme acitivy B Le parent de l'enfant dans AndroidManifest.xml en utilisant à la fois le android:parentActivityName et l'attribut correspondant meta-data pour les versions antérieures d'Android (voir " Fournir une navigation vers le haut ").

Déjà sans code de création correspondant tel que getActionBar() .setHomeButtonEnabled(true) l'activité B a un bouton retour fonctionnel ( < ) dans sa barre d'action. Lorsque vous appuyez sur ce bouton, l'activité A réapparaît mais avec (a) tous les états d'instance précédents sont perdus, (b) onCreate toujours appelé, et (c) savedInstanceState toujours null .

Il est intéressant de noter que lorsque j'appuie sur le bouton de retour prévu à cet effet sur le bord inférieur de l'écran de l'émulateur (un triangle ouvert qui pointe vers la gauche), l'activité A réapparaît tel qu'il a été laissé (c.-à-d. que son état d'instance est entièrement conservé) sans invoquer l'option onCreate . Il y a donc peut-être un problème de navigation ?

Après plus de lecture j'ai implémenté mes propres instructions de navigation pour qu'elles s'exécutent en réponse à une pression sur le bouton arrière en activité. B :

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == android.R.id.home)
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Rien concernant le rétablissement de l'état d'activité de l'instance A changé. NavUtils fournissent également une méthode getParentActivityIntent(Activity) y navigateUpTo(Activity, Intent) qui nous permettent de modifier l'intention de navigation pour demander explicitement que l'activité A n'est pas démarré fraîchement (et donc sans état d'instance sauvegardé fourni) par la définition de l'attribut FLAG_ACTIVITY_CLEAR_TOP drapeau :

Si elle est définie, et que l'activité en cours de lancement est déjà exécutée dans la tâche en cours, au lieu de lancer une nouvelle instance de cette activité activité, toutes les autres activités situées au-dessus seront fermées et l'activité en cours de lancement est déjà en cours d'exécution dans la tâche actuelle. nouvel Intent.

Dans mes mains, cela résout le problème de l'état d'instance perdu et pourrait ressembler à ceci :

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()== android.R.id.home) {
        Intent intent = NavUtils.getParentActivityIntent(this);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        NavUtils.navigateUpTo(this, intent);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Notez que cela peut ne pas être la solution complète dans d'autres cas où un utilisateur peut passer directement à l'activité B à partir d'une autre tâche (voir aquí ). De même, une solution éventuellement identique dans le comportement qui ne fait pas appel à la fonction NavUtils est de simplement appeler finish() :

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()== android.R.id.home) {
        finish();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Les deux solutions fonctionnent dans mes mains. Je ne fais que spéculer que le problème original est une implémentation par défaut légèrement incorrecte du bouton arrière, et il peut être lié à cette implémentation invoquant une sorte de navigateUp qui manque FLAG_ACTIVITY_CLEAR_TOP .

15voto

mxcl Points 5921

L'état sauvegardé de cette manière n'est pas persisté. Si l'application entière est tuée, comme vous le faites pendant le débogage, le paquet sera toujours nul dans le fichier onCreate .

Cet OMI est un nouvel exemple de l'horrible documentation Android. C'est aussi la raison pour laquelle la plupart des applications sur le marché n'implémentent pas correctement la sauvegarde de l'état (du tout).

2 votes

C'est donc uniquement pour les changements d'orientation de l'écran, etc.

8 votes

Je suis tout à fait d'accord avec l'expression "documentation affreuse".

1 votes

Fabian, l'état sauvegardé sera toujours en théorie créé lorsque l'activité est détruite puis recréée, il est juste impossible de tester cette éventualité. IME ce cas d'utilisation fait se produire.

14voto

PHF Points 164

Avez-vous vérifié si vous avez un Id défini pour cette vue (si c'est une vue...). onSaveInstanceState() n'est pas appelé sinon.

Vérifiez ceci lien .

3 votes

Cette réponse semble sans rapport avec le problème posé. Med a déclaré que onSaveInstanceState() est toujours appelé, donc le problème n'est pas que onSaveInstanceState() ne soit pas appelé.

8voto

Al Khorazmiy Points 106

Dans le manifeste, ajoutez cette ligne pour les activités

android:launchMode="singleTop"

par exemple :

<activity
        android:name=".ActivityUniversity"
        android:label="@string/university"
        android:launchMode="singleTop"
        android:parentActivityName="com.alkhorazmiy.dtm.ActivityChart">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.alkhorazmiy.dtm.ActivityChart" />
    </activity>

1 votes

Que fait exactement la spécification de cette ligne pour une activité ?

0 votes

@DavidLire la réponse tardive mais, marquant l'activité comme singleTop fait en sorte que, s'il y a une activité existante en arrière-plan, elle est utilisée. If, when starting the activity, there is already an instance of the same activity class in the foreground that is interacting with the user, then re-use that instance. This existing instance will receive a call to onNewIntent() with the new Intent that is being started. Vous devez juste passer outre onNewIntent() après dans l'activité. Avec onResume mon uri était nul avec standard y singleInstance l'a recréé en raison de la mort du processus.

3voto

mibollma Points 5389

Comment le testez-vous ?

La meilleure façon de le tester est d'utiliser l'option "Ne pas conserver les activités" dans Paramètres > Options du développeur. Si vous n'avez pas d'Options du développeur dans les Paramètres, voir Activation des options du développeur sur l'appareil .

  1. Ouvrez votre activité
  2. Appui long sur la maison
  3. Aller à une autre application
  4. Appui long sur la maison
  5. Retournez à votre application

0 votes

Les DevTools ne fonctionnent que dans l'émulateur. Si vous voulez tester sur un appareil réel en utilisant la même méthode, utilisez l'outil SetAlwaysFinish. Voir cette réponse pour plus de détails : stackoverflow.com/a/8621269/483708

0 votes

Les options du développeur sont désormais disponibles sur tous les appareils.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X