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?


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.


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 ...


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();

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());
            }
        });
    }
}

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();

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.


4

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


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!


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();

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 ;)


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();

-9

Pourquoi pas seulement:

getActivity (). finish ();


4
Cela terminera toute l'activité et pas seulement le fragment.
Murtadha S.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.