171 votes

Comment puis-je maintenir fragment de l'état lorsqu'il est ajouté à la pile de retour?

J'ai écrit un mannequin d'activité qui permet de commuter entre les deux fragments. Quand vous allez de FragmentA à FragmentB, FragmentA est ajouté à la pile de retour. Cependant, quand je retourne à FragmentA (en appuyant sur l'arrière), un tout nouveau FragmentA est créé et l'état est perdu. J'ai le sentiment que je suis après la même chose que cette question, mais j'ai inclus un exemple de code complet pour aider à la racine de la question:

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

Avec certains messages du journal a ajouté:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

Il n'est jamais appel FragmentA.onSaveInstanceState et il crée un nouveau FragmentA lorsque vous frapper en retour. Cependant, si je suis sur FragmentA et je verrouiller l'écran, FragmentA.onSaveInstanceState est appelé. Tellement bizarre...je suis mal dans l'attente d'un fragment ajouté à la pile de retour pour ne pas avoir besoin de re-création? Voici ce que les docs disent:

Tandis que si vous faites appel addToBackStack() lors de la suppression d'un fragment, puis le fragment est arrêté et sera repris si l'utilisateur navigue de retour.

125voto

Jan-Henk Points 2860

Si vous revenez à un fragment de la pile de retour, il n'a pas re-créer le fragment, mais ré-utilise la même instance et commence par onCreateView() dans le fragment du cycle de vie, voir le Fragment du cycle de vie.

Donc, si vous voulez stocker l'état, vous devez utiliser les variables d'instance et de ne pas s'appuyer sur onSaveInstanceState().

81voto

Vince Yuan Points 1735

Comparer Apple à l' UINavigationController et UIViewController, Google ne fait pas bien dans le logiciel Android de l'architecture. Et Android du document sur l' Fragment n'aide pas beaucoup.

Lorsque vous entrez FragmentB de FragmentA, les FragmentA instance n'est pas détruit. Lorsque vous appuyez sur la touche de Retour dans FragmentB et retour à FragmentA, nous ne créons pas une nouvelle FragmentA instance. L'existant FragmentA de l'instance de l' onCreateView() sera appelée.

La clé, c'est qu'on ne doit pas gonfler à vue est de nouveau dans les FragmentA de l' onCreateView(), parce que nous sommes les FragmentA de l'instance. Nous avons besoin d'enregistrer et de réutiliser les rootView.

Le code suivant fonctionne bien. Il ne garde pas seulement fragment de l'état, mais aussi de réduire la RAM et la charge CPU (parce que nous ne gonflent mise en page si nécessaire). Je ne peux pas croire que Google est un exemple de code de document et de ne jamais le mentionner, mais toujours gonfler mise en page.

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

55voto

kaushal trivedi Points 1288

Je pense qu'il y a un autre moyen d'obtenir ce que vous cherchez. Je ne dis pas que sa solution complète, mais il a servi le but dans mon cas.

Ce que j'ai fait est qu'au lieu de remplacer le fragment, j'ai juste ajouté fragment cible. Donc, fondamentalement, vous allez utiliser add() méthode de replace().

Quoi d'autre que j'ai fait. - Je cacher mon fragment et aussi l'ajouter à la backstack.

Par conséquent, il chevauche nouveau fragment cours, fragment sans détruire son point de vue.(vérifier que son onDestroyView() méthode n'est pas appelée.En Plus de l'ajouter, backstate me donne l'avantage de reprendre le fragment.

Voici le code :

            Fragment fragment=new DestinationFragment();
            FragmentManager fragmentManager = getFragmentManager();
            android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
            ft.add(R.id.content_frame, fragment);
            ft.hide(SourceFragment.this);
            ft.addToBackStack(SourceFragment.class.getName());
            ft.commit();

Autant que je sache seulement au Système d'appels onCreateView si la vue est détruit ou n'ont pas créé. Mais ici, nous avons sauvé le point de vue en ne retirant pas de mémoire.Afin de ne pas créer une nouvelle vue.

Et lorsque vous revenez de Destination Fragment de il pop le dernier FragmentTransaction retrait fragment du haut qui va faire le plus haut(SourceFragment s) vue à apparaître sur l'écran.

COMMENTAIRE :Comme je l'ai dit ce n'est pas une solution complète car elle ne permet pas de supprimer l'affichage de la Source du fragment et, partant, occupant plus de mémoire que d'habitude.Mais encore servir le but.Nous sommes également à l'aide d'un mécanisme totalement différent de se cacher de la vue au lieu de les remplacer, ce qui est non traditionnels.

Donc ce n'est pas vraiment de la façon dont vous maintenir à l'état,mais de la façon dont vous gérer la vue.

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