J'ai un énorme problème avec la façon dont la backstack de fragments Android semble fonctionner et je serais très reconnaissant pour toute aide qui est offerte.
Imaginez que vous avez 3 fragments
[1] [2] [3]
Je veux que l'utilisateur puisse naviguer [1] > [2] > [3]
mais sur le chemin du retour (en appuyant sur le bouton retour) [3] > [1]
.
Comme je l'aurais imaginé, cela serait accompli en n'appelant pas addToBackStack(..)
lors de la création de la transaction qui [2]
introduit le fragment dans le détenteur du fragment défini en XML.
La réalité de cela semble que si je ne veux [2]
pas réapparaître lorsque l'utilisateur appuie sur le bouton retour [3]
, je ne dois pas appeler addToBackStack
la transaction qui montre le fragment [3]
. Cela semble complètement contre-intuitif (peut-être venant du monde iOS).
Quoi qu'il en soit, si je le fais de cette façon, quand je pars [1] > [2]
et que j'appuie, j'arrive [1]
comme prévu.
Si j'y vais [1] > [2] > [3]
et que j'appuie, je reviens à [1]
(comme prévu). Maintenant, le comportement étrange se produit lorsque j'essaye de sauter à [2]
nouveau à partir de [1]
. Tout d'abord [3]
est brièvement affiché avant d' [2]
entrer en vue. Si j'appuie en arrière à ce stade [3]
s'affiche, et si j'appuie à nouveau, l'application se ferme.
Quelqu'un peut-il m'aider à comprendre ce qui se passe ici?
Et voici le fichier xml de mise en page pour mon activité principale:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<fragment
android:id="@+id/headerFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.fragment_test.FragmentControls" >
<!-- Preview: layout=@layout/details -->
</fragment>
<FrameLayout
android:id="@+id/detailFragment"
android:layout_width="match_parent"
android:layout_height="fill_parent"
/>
Mettre à jour C'est le code que j'utilise pour construire par nav heirarchy
Fragment frag;
FragmentTransaction transaction;
//Create The first fragment [1], add it to the view, BUT Dont add the transaction to the backstack
frag = new Fragment1();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.commit();
//Create the second [2] fragment, add it to the view and add the transaction that replaces the first fragment to the backstack
frag = new Fragment2();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.addToBackStack(null);
transaction.commit();
//Create third fragment, Dont add this transaction to the backstack, because we dont want to go back to [2]
frag = new Fragment3();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.commit();
//END OF SETUP CODE-------------------------
//NOW:
//Press back once and then issue the following code:
frag = new Fragment2();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.addToBackStack(null);
transaction.commit();
//Now press back again and you end up at fragment [3] not [1]
Merci beaucoup
la source
Réponses:
Explication: qu'est-ce qui se passe ici?
Si nous gardons à l'esprit que cela
.replace()
équivaut à ce.remove().add()
que nous savons par la documentation:alors ce qui se passe est comme ça (j'ajoute des nombres au frag pour le rendre plus clair):
(ici toutes les choses trompeuses commencent à se produire)
N'oubliez pas que
.addToBackStack()
c'est enregistrer uniquement la transaction et non le fragment comme lui-même! Alors maintenant, nous avonsfrag3
sur la mise en page:Solution possible
Envisagez de mettre
FragmentManager.BackStackChangedListener
en œuvre pour surveiller les changements dans la pile arrière et appliquez votre logique dans laonBackStackChanged()
méthode:FragmentTransaction.addToBackStack(String name);
la source
FragmentManager.BackStackChangedListener
pour surveiller les modifications apportées à la pile arrière. Surveillez toutes vos transactions aveconBackStackChanged()
méthode et agissez si nécessaire: par ex. tracez le décompte des transactions dans BackStack; vérifier une transaction particulière par nom (FragmentTransaction addToBackStack (String name)
) etc.Droite!!! après avoir beaucoup arraché les cheveux, j'ai enfin trouvé comment faire fonctionner correctement.
Il semble que le fragment [3] ne soit pas supprimé de la vue lorsque vous appuyez sur Back, vous devez donc le faire manuellement!
Tout d'abord, n'utilisez pas replace () mais utilisez plutôt remove et add séparément. Il semble que replace () ne fonctionne pas correctement.
La prochaine étape consiste à remplacer la méthode onKeyDown et à supprimer le fragment actuel chaque fois que vous appuyez sur le bouton Précédent.
J'espère que cela t'aides!
la source
Tout d'abord merci @Arvis pour une explication révélatrice.
Je préfère une solution différente à la réponse acceptée ici pour ce problème. Je n'aime pas jouer avec le comportement de retour de priorité pas plus que ce qui est absolument nécessaire et quand j'ai essayé d'ajouter et de supprimer des fragments par moi-même sans que la pile de retour par défaut n'apparaisse lorsque le bouton de retour est enfoncé, je me suis retrouvé dans l'enfer des fragments :) Si vous. ajoutez f2 sur f1 lorsque vous le supprimez f1 n'appellera aucune des méthodes de rappel comme onResume, onStart etc. et cela peut être très malheureux.
Quoi qu'il en soit, voici comment je le fais:
Actuellement, seul le fragment f1 est affiché.
f1 -> f2
rien d'extraordinaire ici. Que dans le fragment f2, ce code vous amène au fragment f3.
f2 -> f3
Je ne suis pas sûr en lisant des documents si cela devrait fonctionner, cette méthode de transaction pop-up est dite asynchrone, et peut-être qu'une meilleure façon serait d'appeler popBackStackImmediate (). Mais pour autant que je sache sur mes appareils, cela fonctionne parfaitement.
Cette alternative serait:
Ici, il y aura en fait un bref retour à f1 avant de passer à f3, donc un léger problème.
C'est en fait tout ce que vous avez à faire, pas besoin de remplacer le comportement de la pile arrière ...
la source
Je sais que c'est une vieille question, mais j'ai le même problème et je le corrige comme ceci:
Tout d'abord, ajoutez Fragment1 à BackStack avec un nom (par exemple "Frag1"):
Et puis, chaque fois que vous voulez revenir à Fragment1 (même après avoir ajouté 10 fragments au-dessus), appelez simplement popBackStackImmediate avec le nom:
J'espère que cela aidera quelqu'un :)
la source
Après la réponse de @Arvis, j'ai décidé de creuser encore plus profondément et j'ai écrit un article technique à ce sujet ici: http://www.andreabaccega.com/blog/2015/08/16/how-to-avoid-fragments-overlapping- en raison du cauchemar-backstack-dans-android /
Pour les développeurs paresseux. Ma solution consiste à toujours ajouter les transactions à la backstack et à effectuer un extra en
FragmentManager.popBackStackImmediate()
cas de besoin (automatiquement).Le code est très peu de lignes de code et, dans mon exemple, je voulais sauter de C à A sans revenir à "B" si l'utilisateur n'allait pas plus loin dans la backstack (ex de C navigue vers D).
Par conséquent, le code joint fonctionnerait comme suit A -> B -> C (retour) -> A & A -> B -> C -> D (retour) -> C (retour) -> B (retour) -> A
où
ont été émis de «B» à «C» comme dans la question.
Ok, ok voici le code :)
la source
Si vous êtes aux prises avec addToBackStack () et popBackStack (), utilisez simplement
Dans votre activité dans OnBackPressed (), découvrez le segment par tag, puis faites vos affaires
Pour plus d'informations https://github.com/DattaHujare/NavigationDrawer, je n'utilise jamais addToBackStack () pour gérer les fragments.
la source
Je pense, quand j'ai lu votre histoire, que [3] est également sur la backstack. Cela explique pourquoi vous le voyez clignoter.
La solution serait de ne jamais mettre [3] sur la pile.
la source
s old method issue but now it
bien. MerciJ'ai eu un problème similaire où j'avais 3 fragments consécutifs dans le même
Activity
[M1.F0] -> [M1.F1] -> [M1.F2] suivi d'un appel à un nouveauActivity
[M2]. Si l'utilisateur appuyait sur un bouton dans [M2], je voulais revenir à [M1, F1] au lieu de [M1, F2], ce que faisait déjà le comportement de contre-pression.Afin d'accomplir ceci je supprime [M1, F2], appelle show sur [M1, F1], valide la transaction, puis ajoute [M1, F2] en l'appelant avec hide. Cela a supprimé la presse arrière supplémentaire qui aurait autrement été laissée pour compte.
Salut Après avoir fait ce code: je ne suis pas en mesure de voir la valeur de Fragment2 en appuyant sur la touche Retour. Mon code:
la source
executePendingTransactions()
,commitNow()
pas travaillé (Travaillé sous androidx (jetpack).
la source