J'ai trouvé de nombreux exemples d'une question similaire sur SO, mais aucune réponse ne répond malheureusement à mes exigences.
J'ai différentes dispositions pour le portrait et le paysage et j'utilise la pile arrière, ce qui m'empêche à la fois d'utiliser setRetainState()
et des astuces en utilisant des routines de changement de configuration.
J'affiche certaines informations à l'utilisateur dans TextViews, qui ne sont pas enregistrées dans le gestionnaire par défaut. Lors de la rédaction de ma candidature en utilisant uniquement des activités, les éléments suivants ont 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 Fragment
s, cela ne fonctionne que dans des situations très spécifiques. Plus précisément, ce qui casse horriblement est de remplacer un fragment, de le placer dans la pile arrière, puis de faire pivoter l'écran pendant 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 en quelque sorte lié à la Activity
et cette méthode est appelée plus tard lorsqu'elle View
n'existe plus, donc je cherche l'un de mes TextView
résultats dans a NullPointerException
.
De plus, j'ai trouvé que garder la référence à mon TextViews
n'est pas une bonne idée avec Fragment
s, même si ça allait avec Activity
. Dans ce cas, onSaveInstanceState()
enregistre réellement l'état mais le problème réapparaît si je fais pivoter l'écran deux fois lorsque le fragment est masqué, car il onCreateView()
n'est pas appelé dans la nouvelle instance.
Je pensais que de sauver l'état onDestroyView()
dans un certain Bundle
élément de membre de classe de type (il est en fait plus de données, pas seulement un TextView
) et les économies que dans , onSaveInstanceState()
mais il y a d' autres inconvénients. Principalement, si le fragment est actuellement affiché, l'ordre d'appeler les deux fonctions est inversé, donc je devrais tenir compte de deux situations différentes. Il doit y avoir une solution plus propre et correcte!
la source
Réponses:
Pour enregistrer correctement l'état de l'instance,
Fragment
procédez comme suit:1. Dans le fragment, enregistrez l'état de l'instance en remplaçant
onSaveInstanceState()
et restaurez dansonActivityCreated()
:2. Et point important , dans l'activité, vous devez enregistrer l'instance du fragment dans
onSaveInstanceState()
et restaurer dansonCreate()
.J'espère que cela t'aides.
la source
C'est la façon dont j'utilise en ce moment ... c'est très compliqué mais au moins ça gère toutes les situations possibles. Au cas où quelqu'un serait intéressé.
Alternativement , il est toujours possible de conserver les données affichées dans des
View
s passifs dans des variables et d'utiliser lesView
s uniquement pour les afficher, en gardant les deux choses synchronisées. Cependant, je ne considère pas la dernière partie très propre.la source
A
etB
, oùA
est actuellement sur le backstack etB
est visible, alors vous perdez l'état deA
(l'invisible un) si vous tournez l'affichage deux fois . Le problème est que ceonCreateView()
n'est pas appelé uniquement dans ce scénarioonCreate()
. Donc, plus tard,onSaveInstanceState()
il n'y a aucune vue pour enregistrer l'état. Il faudrait stocker puis sauvegarder l'état passéonCreate()
.App.VSTUP
etApp.STAV
sont les deux balises de chaîne qui représentent les objets qu'ils tentent d'obtenir. Exemple:savedState = savedInstanceState.getBundle(savedGamePlayString);
ousavedState.getDouble("averageTime")
Sur la dernière bibliothèque de support, aucune des solutions discutées ici n'est plus nécessaire. Vous pouvez jouer avec vos
Activity
fragments comme vous le souhaitez en utilisant leFragmentTransaction
. Assurez-vous simplement que vos fragments peuvent être identifiés avec un identifiant ou une balise.Les fragments seront restaurés automatiquement tant que vous n'essayez pas de les recréer à chaque appel à
onCreate()
. Au lieu de cela, vous devez vérifier sisavedInstanceState
n'est pas nul et trouver les anciennes références aux fragments créés dans ce cas.Voici un exemple:
Notez cependant qu'il existe actuellement un bogue lors de la restauration de l'état caché d'un fragment. Si vous cachez des fragments dans votre activité, vous devrez restaurer cet état manuellement dans ce cas.
la source
FragmentPagerAdapter
ouFragmentStatePagerAdapter
. Si vous regardez le code deFragmentStatePagerAdapter
, par exemple, vous verrez que larestoreState()
méthode restaure les fragments duFragmentManager
paramètre que vous avez transmis lors de la création de l'adaptateur.Je veux juste donner la solution que j'ai trouvée qui gère tous les cas présentés dans ce post que j'ai dérivés de Vasek et de devconsole. Cette solution gère également le cas spécial lorsque le téléphone est tourné plusieurs fois alors que les fragments ne sont pas visibles.
Voici où je stocke le bundle pour une utilisation ultérieure, car onCreate et onSaveInstanceState sont les seuls appels effectués lorsque le fragment n'est pas visible
Étant donné que destroyView n'est pas appelé dans la situation de rotation spéciale, nous pouvons être certains que s'il crée l'état, nous devons l'utiliser.
Cette partie serait la même.
Maintenant ici est la partie la plus délicate. Dans ma méthode onActivityCreated j'instancie la variable "myObject" mais la rotation se produit onActivity et onCreateView ne sont pas appelés. Par conséquent, myObject sera nul dans cette situation lorsque l'orientation pivote plusieurs fois. Je contourne cela en réutilisant le même bundle qui a été enregistré dans onCreate que le bundle sortant.
Maintenant, où que vous vouliez restaurer l'état, utilisez simplement le bundle saveState
la source
Grâce à DroidT , j'ai réalisé ceci:
Je me rends compte que si le fragment n'exécute pas onCreateView (), sa vue n'est pas instanciée. Donc, si le fragment sur la pile arrière n'a pas créé ses vues, j'enregistre le dernier état stocké, sinon je crée mon propre bundle avec les données que je veux enregistrer / restaurer.
1) Etendez cette classe:
2) Dans votre fragment, vous devez avoir ceci:
3) Par exemple, vous pouvez appeler hasSavedState dans onActivityCreated:
la source
la source