534 votes

Comment sauvegarder correctement l'état d'instance des fragments dans la pile arrière ?

J'ai trouvé de nombreuses occurrences d'une question similaire sur SO mais malheureusement aucune réponse ne répond à mes exigences.

J'ai des mises en page différentes pour le portrait et le paysage et j'utilise la pile arrière, ce qui m'empêche d'utiliser setRetainState() et des astuces utilisant les routines de changement de configuration.

J'affiche certaines informations à l'utilisateur dans des TextView, qui ne sont pas enregistrées dans le gestionnaire par défaut. Lorsque j'ai écrit mon application en utilisant uniquement des Activities, ce qui suit a bien fonctionné :

TextView vstup;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.whatever);
    vstup = (TextView)findViewById(R.id.whatever);
    /* (...) */
}

@Override
public void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);
    state.putCharSequence(App.VSTUP, vstup.getText());
}

@Override
public void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);
    vstup.setText(state.getCharSequence(App.VSTUP));
}

Avec des Fragments, cela fonctionne uniquement dans des situations très spécifiques. En particulier, ce qui se casse horriblement, c'est le remplacement d'un fragment, sa mise dans la pile arrière, puis la rotation de l'écran alors que le nouveau fragment est affiché. D'après ce que j'ai compris, l'ancien fragment ne reçoit pas d'appel à onSaveInstanceState() lorsqu'il est remplacé mais reste d'une certaine manière lié à l'Activity et cette méthode est appelée plus tard lorsque sa View n'existe plus, donc chercher l'un de mes TextViews entraîne une NullPointerException.

J'ai également constaté que conserver la référence à mes TextViews n'est pas une bonne idée avec les Fragments, même si c'était correct avec les Activitys. Dans ce cas, onSaveInstanceState() enregistre effectivement l'état mais le problème réapparaît si je tourne l'écran deux fois lorsque le fragment est caché, car son onCreateView() n'est pas appelé dans la nouvelle instance.

J'ai pensé à enregistrer l'état dans onDestroyView() dans un élément de type Bundle (en fait, il s'agit de plusieurs données, pas seulement un TextView) et enregistrer celui-ci dans onSaveInstanceState() mais il y a d'autres inconvénients. Principalement, si le fragment est actuellement affiché, l'ordre d'appel des deux fonctions est inversé, donc je dois prendre en compte deux situations différentes. Il doit exister une solution plus propre et correcte !

1 votes

Voici un très bon exemple avec une explication détaillée également. emuneee.com/blog/2013/01/07/saving-fragment-states

1 votes

Je soutiens le lien emunee.com. Cela a résolu un problème d'interface utilisateur pour moi !

-9voto

Nilesh Savaliya Points 520
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.hide(currentFragment);
ft.add(R.id.content_frame, newFragment.newInstance(context), "Profil");
ft.addToBackStack(null);
ft.commit();

1 votes

Pas liée à la question initiale.

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