Comment les opérations popBackStack() et replace() diffèrent-elles?

J'ai rencontré un comportement curieux dans mon application lors de la gestion des Fragments et je me demandais si cela pouvait aider à faire la lumière sur pourquoi cela se produit.

J'ai deux Fragments, nous les appellerons Fragment A et Fragment B. Le flux général de mon application est que lorsque l'utilisateur interagit avec le Fragment A d'une manière ou d'une autre, le Fragment B est affiché en appelant fragmentTransaction.replace() (cela arrive dans tous les cas). Quand je montre le Fragment B, j'ajoute le Fragment A à la pile arrière; puis, lorsque l'utilisateur appuie sur le bouton Retour sur le Fragment B, Le Fragment A est montré à nouveau en sortant de la pile arrière.

C'est bien, mais aujourd'hui j'ai découvert qu'il y a un flux de Fragment B qui appelle fragmentTransaction.replace(), en remplaçant le Fragment B par la même instance de Fragment A qui est actuellement sur la pile arrière.

En soi, il n'y a rien de mal à cela, mais le comportement étrange se produit quand je reviens du Fragment A au Fragment B. Si j'ai appelé fragmentTransaction.replace(), la méthode onCreate() du Fragment B n'est pas appelé.

Cependant, si j'ai sauté le Fragment A de la pile arrière et l'ai ensuite remplacé par le Fragment B, la méthode onCreate() du Fragment B est déclenchée. Pourquoi est-ce?

Notez que toutes les instances du Fragment A et du Fragment B sont créées au moment du lancement de leur activité hôte.

Modifier pour clarifier. Le cas où onCreate() est appelée une deuxième fois est la suivante: Fixer Un Fragment => remplacer par du Fragment B, l'ajout d'Un Fragment à l'arrière de la pile => pop-Fragment d'Une aide popBackStack() = > remplacez le Fragment A par le Fragment B.

22
demandé sur Jonathan 2013-07-22 21:00:19

2 réponses

replace() fait 2 choses:

  1. supprimer le fragment (a) actuellement ajouté du conteneur (c) que vous avez indiqué
  2. Ajouter un nouveau fragment (B) au même conteneur

Ces 2 opérations sont ce qui est enregistré en tant Qu'enregistrement / transaction Backstack. Notez que le fragment A reste dans l'état created, et sa vue est détruite.

Maintenant popBackStack() inverse votre dernière transaction que vous avez ajoutée à BackStack.

Dans ce cas, ce serait 2 étapes:

  1. Supprimer B de C
  2. Ajouter A à C

Après cela, le fragment B devient detached, et si vous n'avez pas conservé de références, il sera collecté.

Pour répondre à la première partie de votre question, il n'y a pas d'appel onCreate(), Car FragmentB est resté dans l'état created. Et la réponse à la deuxième partie de la question est un peu plus longue.

Tout d'abord, il est important de comprendre que vous n'ajoutez pas réellement Fragments à Backstack, vous ajoutez FragmentTransactions. Ainsi, lorsque vous pensez que vous "remplacez par le Fragment B, en ajoutant le Fragment A à la pile arrière" , vous ajoutez en fait toute cette opération à backstack - c'est-à-dire remplacement De A avec B. Ce remplacement se compose de 2 actions-supprimer A et ajouter B.

Ensuite, l'étape suivante consiste à afficher la transaction contenant ce remplacement. Donc, vous ne sautez pas FragmentA, vous inversez "Supprimer A, Ajouter B", qui est inversé "supprimer B, ajouter A".

Et puis l'étape finale devrait être plus claire-il n'y a pas B dont FragmentManager est conscient, donc lorsque vous l'ajoutez en remplaçant A par B à votre dernière étape, B doit passer par ses méthodes de cycle de vie précoce - onAttach() et onCreate().

Le Code ci-dessous illustre ce qui se passe.

FragmentManager fm  = getFragmentManager();
FragmentA fragmentA = new FragmentA();
FragmentB fragmentB = new FragmentB();

// 1. Show A
fm.beginTransaction()
  .add(fragmentA, R.id.container)
  .commit();

// 2. Replace A with B
// FragmentManager keeps reference to fragmentA;
// it stays attached and created; fragmentB goes 
// through lifecycle methods onAttach(), onCreate()
// and so on.
fm.beginTransaction()
  .replace(fragmentB, R.id.container)
  .addToBackstack(null)
  .commit();

// 2'. Alternative to replace() method
fm.beginTransaction()
  .remove(fragmentA)
  .add(fragmentB, R.id.container)
  .addToBackstack(null)
  .commit();

// 3. Reverse (2); Result - A is visible
// What happens:
//   1) fragmentB is removed from container, it is detached now;
//      FragmentManager doesn't keep reference to it anymore
//   2) Instance of FragmentA is placed back in the container
// Now your Backstack is empty, FragmentManager is aware only
// of FragmentA instance
fm.popBackStack();

// 4. Show B
// Since fragmentB was detached, it goes through its early
// lifecycle methods: onAttach() and onCreate().
fm.beginTransaction()
  .replace(fragmentB, R.id.container)
  .addToBackstack(null)
  .commit();
71
répondu mindeh 2013-07-22 20:02:11

C'est peut-être parce que le gestionnaire de fragments réutilise l'instance de fragment plutôt que de la recréer. Si le code à l'intérieur du Fragment B onCreate() doit être exécuté lorsque le fragment est affiché, déplacez le code dans une autre méthode comme onResume().

0
répondu tbruyelle 2013-07-22 17:28:29