Comment supprimer correctement un DialogFragment?

121

La documentation dit ceci pour la dismiss()méthode de la Dialogclasse:

Fermez cette boîte de dialogue et supprimez-la de l'écran. Cette méthode peut être appelée en toute sécurité depuis n'importe quel thread. Notez que vous ne devez pas remplacer cette méthode pour effectuer le nettoyage lorsque la boîte de dialogue est fermée, mais implémentez-la dans onStop().

Dans mon code, tout ce que je fais est d'appeler getDialog().dismiss()pour le rejeter. Mais je ne fais rien d'autre ni même n'utilise onStop(). Je demande donc exactement comment écarter correctement un DialogFragmentpour éviter toute fuite de mémoire, etc.

Andy
la source

Réponses:

197

tl; dr: La manière correcte de fermer a DialogFragmentest de l'utiliser dismiss() directement sur le DialogFragment .


Détails : La documentation des états de DialogFragment

Le contrôle de la boîte de dialogue (décider quand l'afficher, la masquer, la fermer) doit être effectuée via l'API ici, et non avec des appels directs sur la boîte de dialogue.

Ainsi, vous ne devriez pas utiliser getDialog().dismiss(), car cela invoquerait dismiss() sur la boîte de dialogue . Au lieu de cela, vous devez utiliser la dismiss()méthode du DialogFragment lui-même:

rejet public nul ()

Ignorez le fragment et sa boîte de dialogue. Si le fragment a été ajouté à la pile arrière, tous les états de pile arrière jusqu'à et y compris cette entrée seront sautés. Sinon, une nouvelle transaction sera validée pour supprimer le fragment.

Comme vous pouvez le voir, cela prend soin non seulement de fermer la boîte de dialogue, mais également de gérer les transactions de fragment impliquées dans le processus.

Vous ne devez l'utiliser que onStopsi vous avez explicitement créé des ressources nécessitant un nettoyage manuel (fermeture de fichiers, fermeture de curseurs, etc.). Même dans ce cas, je remplacerais onStople DialogFragment plutôt que onStople Dialog sous-jacent.

Heinzi
la source
1
@ScootrNova: Cela ne devrait pas, vous avez probablement un bogue ailleurs. Comment créez-vous le fragment?
Heinzi
protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Désolé pour la vilaine doublure! Mais oui, vous pourriez avoir raison, donc pour le moment, j'ai écrit une autre façon de fermer mes DialogFragments. La façon dont je les rejetais à l'aide de la méthode rejet () consistait simplement à trouver le fragment par balise, puis à exécuter rejeter () dessus s'il n'était pas nul. Oh et oui, je suis newle fragment juste avant de le passer à cette méthode.
Charles Madere
2
@ScootrNova: Hmm, ne vois rien de mal à cela - d'un autre côté, je n'ai jamais utilisé la bibliothèque de compatibilité, donc je ne peux pas en être sûr. Il serait peut-être judicieux de créer un exemple minimal et autonome et de commencer une nouvelle question à ce sujet.
Heinzi
@CharlesMadere à l'époque, avez-vous trouvé une solution?
JCarlosR
Désolé @JCarlos, c'était il y a des années, je ne suis pas sûr.
Charles Madere
76

Je pense qu'une meilleure façon de fermer un DialogFragmentest la suivante:

Fragment prev = getSupportFragmentManager().findFragmentByTag("fragment_dialog");
if (prev != null) {
    DialogFragment df = (DialogFragment) prev;
    df.dismiss();
}

De cette façon, vous n'avez pas à tenir une référence au DialogFragmentet pouvez le fermer de partout.

Terel
la source
7

Pourquoi n'essayez-vous pas d'utiliser uniquement ce code:

dismiss();

Si vous souhaitez supprimer le fragment de dialogue par lui-même. Vous pouvez simplement placer ce code dans le fragment de boîte de dialogue où vous souhaitez fermer la boîte de dialogue.

Par exemple:

button.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       dismiss();
   }
});

Cela fermera le fragment de dialogue récent affiché à l'écran.

J'espère que cela vous aidera.

Shiva Tiwari
la source
ne travaille pas tout le temps
Mahmoud Heretani
5

J'ai donné un vote favorable à la réponse de Terel. Je voulais juste publier ceci pour tous les utilisateurs de Kotlin:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}
JustinMorris
la source
Le code simple fonctionne dur, merci pour le copain de mise à jour !!
Ayush Katuwal
4

Version Kotlin de la réponse Terel

(fragmentManager.findFragmentByTag(TAG) as? DialogFragment)?.dismiss()
Phil
la source
1

Vous devriez vous rejeter DialogdansonPause() remplacer il.

Aussi avant de rejeter, vous pouvez vérifier nullet s'affiche comme ci-dessous l'extrait de code:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}
Venky
la source
il a déjà écrit qu'il est en train de rejeter () et que c'est à propos de DialogFragment.
Paresh Mayani
Je pense que cela fonctionne à la fois pour Dialog et DialogFragments @PareshMayani
Venky
2
Je pense que @PareshMayani a raison Venky. Le tutoriel sur DialogFragmentpar google ne montre pas du tout la onPause()méthode utilisée. Mais je pense que je vois ce que vous faites. Quel est le point si l'utilisateur n'appelle pas onPause(). C'est quand le système sait que le fragment est appelé. Et quand, par exemple, un utilisateur annule. Quelle est la meilleure façon de le fermer dans ce cas?
Andy
1

Il y a des références aux documents officiels ( DialogFragment Reference ) dans d'autres réponses, mais aucune mention de l'exemple qui y est donné:

void showDialog() {
    mStackLevel++;

    // DialogFragment.show() will take care of adding the fragment
    // in a transaction.  We also want to remove any currently showing
    // dialog, so make our own transaction and take care of that here.
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment prev = getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    // Create and show the dialog.
    DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
    newFragment.show(ft, "dialog");
}

Cela supprime toute boîte de dialogue actuellement affichée, crée un nouveau DialogFragment avec un argument et l'affiche comme un nouvel état sur la pile arrière. Lorsque la transaction est sautée, le DialogFragment actuel et sa boîte de dialogue seront détruits et le précédent (le cas échéant) ré-affiché. Notez que dans ce cas, DialogFragment se chargera de faire sauter la transaction de la boîte de dialogue est rejetée séparément de celui-ci.

Pour mes besoins, je l'ai changé en:

FragmentManager manager = getSupportFragmentManager();
Fragment prev = manager.findFragmentByTag(TAG);
if (prev != null) {
    manager.beginTransaction().remove(prev).commit();
}

MyDialogFragment fragment = new MyDialogFragment();
fragment.show(manager, TAG);
Maksim Ivanov
la source
1

En ajoutant aux autres réponses, lorsque vous avez un DialogFragmentappel en plein écran, dismiss()le DialogFragment ne sort pas de la pile de fragments. Une solution de contournement consiste à appeler onBackPressed()l'activité parent.

Quelque chose comme ça:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}
Mikehc
la source
Sauvez la mise, merci beaucoup
Mahmoud Heretani
0

Appelez simplement la fonction de renvoi () à partir du fragment que vous souhaitez supprimer.

imageView3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dismiss();
        }
    });
VIVEK CHOUDHARY
la source
0

J'ai trouvé que lorsque mon fragment était défini dans le graphique de navigation avec une <fragment>balise (pour un fragment de dialogue en plein écran), le fragment de dialogue ne disparaissait pas avec la dismiss()commande. Au lieu de cela, j'ai dû faire apparaître la pile arrière:

findNavController(getActivity(), R.id.nav_host_fragment).popBackStack();

Cependant, si le même fragment de dialogue a été défini dans le graphique de navigation avec une <dialog>balise, dismiss()fonctionne correctement.

Jon
la source
0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}
Victor Odiah
la source