Comment faire pour supprimer un Fragment, c'est-à-dire son équivalent de finish ()?

230

Je convertis une application pour utiliser des fragments à l'aide de la bibliothèque de compatibilité. Maintenant, j'ai actuellement un certain nombre d'activités (ABCD) qui s'enchaînent les unes aux autres, D a un bouton `` OK '' qui, lorsque vous appuyez, termine, qui ensuite bouillonne onActivityResult()pour détruire C et B.

Pour ma version antérieure au fragment Honycomb, chaque activité est en fait une enveloppe sur les fragments Af Bf Cf Df. Toutes les activités sont lancées via startActivityForResult()et onActivityResult()dans chacun des fragments peuvent heureusement appelergetActivity().finish()

Le problème que je rencontre est que dans ma version Honeycomb, je n'ai qu'une seule activité, A, et les fragments Bf, Cf, Df sont chargés à l'aide de FragmentManager.

Ce que je ne comprends pas, c'est quoi faire dans Df lorsque "OK" est pressé afin de supprimer les fragments Df, Cf et Bf?

J'ai essayé de faire sortir le fragment de la pile, mais cela a entraîné une exception. onActivityResult()est inutile car je n'ai pas chargé le fragment en utilisant startActivityForResult().

Suis-je en train de penser à cela complètement de la mauvaise façon? Dois-je implémenter une sorte d'écouteur qui communique avec le fragment parent ou l'activité afin de faire le pop à l'aide du gestionnaire de transactions?

PJL
la source
7
qu'en est-il de ((YourActivity) getActivity ()). onBackPressed ();
Viswanath Lekshmanan
@ViswanathLekshmanan la réponse de votre commentaire est utile pour moi .. 1 Vote positif de moi
Abhishek Singh
@AbhishekSingh Bon à entendre :)
Viswanath Lekshmanan
@ViswanathLekshmanan :)
Abhishek Singh

Réponses:

62

Ce que je ne comprends pas, c'est quoi faire dans Df lorsque "OK" est pressé afin de supprimer les fragments Df, Cf et Bf?

Étape # 1: Demandez à Df de dire à D "yo! Nous avons obtenu le clic OK!" via l'appel d'une méthode, soit sur l'activité elle-même, soit sur une instance d'interface fournie par l'activité.

Étape # 2: Demandez à D de retirer les fragments via FragmentManager.

L'activité d'hébergement (D) est celle qui sait quels autres fragments se trouvent dans l'activité (vs être dans d'autres activités). Par conséquent, les événements in-fragment qui pourraient affecter le mélange de fragments doivent être propagés à l'activité, ce qui effectuera les mouvements d'orchestration appropriés.

CommonsWare
la source
Mais dans ma version Honeycomb il n'y a pas de D, c'est mon difficile. Il y a simplement une activité A qui charge le fragment Bf, qui charge Cf, qui charge Df en utilisant FragmentTransaction.
PJL
1
@PJL: Désolé, je voulais dire A. C'est une raison d'utiliser une interface d'écoute, donc plusieurs activités peuvent toutes répondre à l'événement "nous avons obtenu le clic OK" de Df.
CommonsWare
1
Pendant que je porte actuellement, j'ai appelé une méthode d'écoute à partir des fragments de la méthode onActivityResult de Df dans l'activité, après quoi j'ai ensuite appelé popBackStack sur le FragmentManager. Cependant, cela se traduit par une exception "IllegalStateException: ne peut pas effectuer cette action après onSaveInstanceState". Des idées sur la façon dont je peux surmonter cela?
PJL
1
@DiegoPalomar: finish()devrait suffire.
CommonsWare
1
@ user3364963: Cela fait un moment que je n'ai pas enquêté, mais IIRC, il est détruit quand il est sorti de la pile arrière. Ajoutez une onDestroy()méthode à votre fragment et voyez si elle est appelée.
CommonsWare
313

Bien que ce ne soit peut-être pas la meilleure approche, l'équivalent le plus proche auquel je peux penser, cela fonctionne avec la bibliothèque de support / compatibilité.

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

ou

getActivity().getFragmentManager().beginTransaction().remove(this).commit();

autrement.

De plus, vous pouvez utiliser le backstack et le faire éclater. Cependant, gardez à l'esprit que le fragment peut ne pas être sur la backstack (en fonction de la transaction de fragment qui l'a amené là-bas ..) ou que ce n'est peut-être pas le dernier qui est entré dans la pile, alors éclater la pile pourrait supprimer le mauvais ...

Manfred Moser
la source
11
Bien que cette approche fonctionne, si vous utilisez addToBackStack (null), elle laissera le gestionnaire de bouton de retour +1. Vous devrez donc appuyer deux fois.
user123321
34
"pop" le fragment du FragmentManager.
user123321
2
J'ai essayé la procédure ci-dessus mais elle donne cette erreur "java-lang-illegalstateexception-can-not-perform-this-action-after-onsaveinstance". Alors où exactement je dois retirer le fragment
KK_07k11A0585
6
Cette réponse est une mauvaise pratique et ne devrait pas faire monter les votes. Les fragments ne sont pas censés être conscients de soi comme ça. Il tue la réutilisabilité, ce qui est le point de fragments! Le fragment doit signaler l'activité de le retirer par n'importe quel nombre de moyens. La méthode de l'interface de rappel est un choix populaire. developer.android.com/training/basics/fragments/…
colintheshots
2
@ManfredMoser Je ne suis pas d'accord. C'est très bien le point de la question. Il a une séquence entière de fragments à retirer. Ce code n'a aucune vérification nulle ou vérifie si l'activité est attachée. Il va s'arrêter en production parce qu'il dépend de trop de choses qu'un fragment ne sait pas.
colintheshots du
263

Vous pouvez utiliser l'approche ci-dessous, cela fonctionne bien:

getActivity().getSupportFragmentManager().popBackStack();
Eric Yuan
la source
44
Cette réponse est 10 fois meilleure que la réponse acceptée - directe.
nikib3ro
50
C'est également 10 fois pire en termes de design que celui accepté. Un fragment est censé être un petit "assistant" à une activité et ne devrait jamais être en contrôle de lui-même ou d'autres fragments
Patrick
6
La solution n'est pas correcte comme l'a souligné @avalancha. Jetez un œil à developer.android.com/guide/components/…
the_dark_destructor
2
J'utilise cette méthode onActivityResult et j'obtiens l'erreur "Impossible d'exécuter cette action après onSaveInstanceState". Comment puis-je le résoudre?
Jayeshkumar Sojitra
1
popBackStack()est la seule solution qui fonctionne lorsque vous souhaitez remettre le titre de la barre d'actions à l'état précédent après avoir supprimé le fragment. Sinon, je n'aurais pas besoin de combiner les deux solutions les mieux notées de stackoverflow.com/questions/13472258/… et cette solution ici pour toujours définir le titre de la barre d'action appropriée après divers cas d'utilisation. comme appuyer en arrière, supprimer, ajouter, remplacer, etc.
Bevor
36

Vous devriez laisser l'activité gérer l'ajout et la suppression de fragments, comme le dit CommonsWare, utilisez un écouteur. Voici un exemple:

public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {

    // onCreate etc

    @Override
    public void onFragmentSuicide(String tag) {
        // Check tag if you do this with more than one fragmen, then:
        getSupportFragmentManager().popBackStack();
    }
}

public interface SuicidalFragmentListener {
    void onFragmentSuicide(String tag);
}

public class MyFragment extends Fragment {

    // onCreateView etc

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
           suicideListener = (SuicidalFragmentListener) activity;
        } catch (ClassCastException e) {
           throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Attach the close listener to whatever action on the fragment you want
        addSuicideTouchListener();
    }

    private void addSuicideTouchListener() {
        getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              suicideListener.onFragmentSuicide(getTag());
            }
        });
    }
}
Blundell
la source
5
Suicide beaucoup de style emo? Que diriez-vous de "SelfClosing" ou "AutoClose" ou "SmartClose" (r)
DritanX
21
ça ne ferme pas c'est DYING FOREVER ;-(
Blundell
3
Il s'agit d'une approche beaucoup plus propre que les autres réponses. L'activité crée et présente le fragment et doit contrôler son cycle de vie. Lorsque quelque chose se produit qui indique que le fragment ne devrait plus être en vue, il doit le signaler à l'activité et laisser l'activité le supprimer.
Christopher Pickslay
7
Techniquement, si nous devons supposer que l'activité tue le fragment, alors le fragment n'est pas suicidaire. L'activité est homicide.
Casey Murray
17

Dans Activity / AppCompatActivity:

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        // if you want to handle DrawerLayout
        mDrawerLayout.closeDrawer(GravityCompat.START);
    } else {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            super.onBackPressed();
        } else {
            getFragmentManager().popBackStack();
        }
    }
}

puis appelez le fragment:

getActivity().onBackPressed();

ou comme indiqué dans d'autres réponses, appelez cela dans le fragment:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
Codeversed
la source
5

Si vous utilisez le nouveau composant de navigation, est aussi simple que

findNavController().popBackStack()

Il fera tout le FragmentTransaction en arrière pour vous.

Gastón Saillén
la source
4

Vérifiez si vos besoins sont satisfaits par un DialogFragment. DialogFragment a une méthode remove (). Beaucoup plus propre à mon avis.

Vasudev
la source
3

Je crée une méthode simple pour ça

popBackStack(getSupportFragmentManager());

Ensuite, placez-le dans ma classe ActivityUtils

public static void popBackStack(FragmentManager manager){
        FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
        manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

C'est un excellent travail, amusez-vous!

Eliasz Kubala
la source
2
Je ne comprends pas le but de votre méthode. Le popBackStack d'origine semble tout à fait adéquat.
L'incroyable
1

OnCreate:

//Add comment fragment
            container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
            mPictureFragment = new fmtAttachPicture();

            var trans = SupportFragmentManager.BeginTransaction();
            trans.Add(container.Id, mPictureFragment, "fmtPicture");
            trans.Show(mPictureFragment); trans.Commit();

Voici comment je cache le fragment dans l'événement de clic 1

//Close fragment
    var trans = SupportFragmentManager.BeginTransaction();
    trans.Hide(mPictureFragment);
    trans.AddToBackStack(null);
    trans.Commit();

Le montre ensuite de retour dans l'événement 2

var trans = SupportFragmentManager.BeginTransaction();
            trans.Show(mPictureFragment); trans.Commit();
CodeSi
la source
1

Si vous devez revenir du quatrième fragment de l'historique de backstack au premier, utilisez des balises !!!

Lorsque vous ajoutez le premier fragment, vous devez utiliser quelque chose comme ceci:

getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit() 

ou

getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()

Et quand vous voulez montrer les fragments B, C et D, vous utilisez ceci:

getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()

et d'autres lettres ....

Pour revenir à FragmentA, appelez simplement popBackStack(0, "A"), oui, utilisez l'indicateur que vous avez spécifié lorsque vous l'ajoutez et notez qu'il doit être le même indicateur dans la commande addToBackStack(), pas celui utilisé dans la commande remplacer ou ajouter.

Vous êtes les bienvenus ;)

Diego Ramírez Vásquez
la source
J'ai testé 'popBackStack (0, "A")' et mon application revient au fragment A, mais je veux seulement que ce fragment soit supprimé de Back Stack ... Comment puis-je supprimer un fragment de Stack sans l'afficher à l'écran ??
KryNaC
1

Pour fermer un fragment à l'intérieur du même fragment

getActivity().onBackPressed();
Dino Sunny
la source
-9

Pourquoi pas seulement:

getActivity (). finish ();

Volonté
la source
4
Cela terminera toute l'activité et pas seulement le fragment.
Murtadha S.