Wie kann ich ein DialogFragment korrekt schließen?


121

Die Dokumente sagen dies für die dismiss()Methode aus der DialogKlasse:

Schließen Sie diesen Dialog und entfernen Sie ihn vom Bildschirm. Diese Methode kann sicher von jedem Thread aus aufgerufen werden. Beachten Sie, dass Sie diese Methode nicht überschreiben sollten, um eine Bereinigung durchzuführen, wenn der Dialog geschlossen wird, sondern diese in implementieren onStop().

In meinem Code rufe ich nur getDialog().dismiss()an, um ihn zu schließen. Aber ich mache nichts anderes oder benutze es gar nicht onStop(). Ich frage also genau, wie man a korrekt DialogFragmentschließt, um Speicherlecks usw. zu vermeiden.

Antworten:


197

tl; dr: Der richtige Weg, a zu schließen, DialogFragmentbesteht darin, es dismiss() direkt im DialogFragment zu verwenden .


Details : Die Dokumentation der DialogFragment- Zustände

Die Steuerung des Dialogfelds (Festlegen, wann es angezeigt, ausgeblendet oder geschlossen werden soll) sollte hier über die API erfolgen, nicht über direkte Aufrufe des Dialogfelds.

Daher sollten Sie nicht verwenden getDialog().dismiss(), da dies dismiss() den Dialog aufrufen würde . Verwenden Sie stattdessen die dismiss()Methode des DialogFragments selbst:

öffentliche nichtige Entlassung ()

Schließen Sie das Fragment und seinen Dialog. Wenn das Fragment zum Backstack hinzugefügt wurde, wird der gesamte Backstack-Status bis einschließlich dieses Eintrags gelöscht. Andernfalls wird eine neue Transaktion festgeschrieben, um das Fragment zu entfernen.

Wie Sie sehen, wird dadurch nicht nur der Dialog geschlossen, sondern auch die am Prozess beteiligten Fragmenttransaktionen behandelt.

Sie müssen nur verwenden, onStopwenn Sie explizit Ressourcen erstellt haben, die manuell bereinigt werden müssen (Schließen von Dateien, Schließen von Cursorn usw.). Selbst dann würde onStopich eher das DialogFragment als onStopden zugrunde liegenden Dialog überschreiben .


1
@ ScootrNova: Es sollte nicht, Sie haben wahrscheinlich einen Fehler woanders. Wie erstellen Sie das Fragment?
Heinzi

protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Entschuldigung für den fiesen Einzeiler! Aber ja, Sie könnten Recht haben, also habe ich vorerst einen anderen Weg geschrieben, um meine DialogFragments zu schließen. Die Art und Weise, wie ich sie mit der Methode submit () entlassen habe, bestand darin, das Fragment nur nach Tag zu suchen und dann entlassen () auszuführen, wenn es nicht null war. Oh und ja, ich mache newdas Fragment kurz bevor ich es an diese Methode weitergebe.
Charles Madere

2
@ScootrNova: Hmm, sehen Sie nichts falsch daran - andererseits habe ich die Kompatibilitätsbibliothek nie verwendet, daher kann ich mir nicht sicher sein. Vielleicht ist es sinnvoll, ein minimales, in sich geschlossenes Beispiel zu erstellen und eine neue Frage dazu zu stellen.
Heinzi

@CharlesMadere, haben Sie damals eine Lösung gefunden?
JCarlosR

Sorry @JCarlos, das war vor Jahren, ich bin mir nicht sicher.
Charles Madere

76

Ich denke, ein besserer Weg, um a zu schließen, DialogFragmentist folgender:

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

Auf diese Weise müssen Sie keinen Verweis auf das halten DialogFragmentund können ihn von überall aus schließen.


8

Warum versuchen Sie nicht, nur diesen Code zu verwenden:

dismiss();

Wenn Sie das Dialogfragment selbst schließen möchten. Sie können diesen Code einfach in das Dialogfragment einfügen, in dem Sie den Dialog schließen möchten.

Beispielsweise:

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

Dadurch wird das zuletzt auf dem Bildschirm angezeigte Dialogfragment geschlossen.

Hoffe es hilft dir.


5

Ich habe Terels Antwort positiv bewertet. Ich wollte dies nur für alle Kotlin-Benutzer posten:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}

Einfacher Code funktioniert hart, Danke für das Update Kumpel !!
Ayush Katuwal

4

Kotlin Version von Terel Antwort

(fragmentManager.findFragmentByTag(TAG) as? DialogFragment)?.dismiss()

1

Sie sollten Sie entlassen Dialogin onPause()so sie überschreiben.

Auch vor dem Entlassen können Sie nach dem nullfolgenden Snippet suchen und es wird angezeigt:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}

Er hat bereits geschrieben, dass er entlassen wird () und es geht um DialogFragment.
Paresh Mayani

Ich denke, das funktioniert sowohl für Dialog als auch für DialogFragments @PareshMayani
Venky

2
Ich glaube @PareshMayani ist richtig Venky. Das Tutorial DialogFragmentvon Google zeigt die verwendete onPause()Methode überhaupt nicht. Aber ich glaube ich sehe was du tust. Was ist der Punkt, wenn der Benutzer nicht anruft onPause(). Dann weiß das System, dass das Fragment abgerufen wird. Was ist mit wann, sagen wir, ein Benutzer storniert. Was ist in diesem Fall ein besserer Weg, um es zu schließen?
Andy

1

In anderen Antworten finden sich Verweise auf die offiziellen Dokumente ( DialogFragment Reference ), das dort angegebene Beispiel wird jedoch nicht erwähnt:

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

Dadurch werden alle aktuell angezeigten Dialoge entfernt, ein neues DialogFragment mit einem Argument erstellt und als neuer Status auf dem Backstack angezeigt. Wenn die Transaktion beendet wird, werden das aktuelle DialogFragment und sein Dialog zerstört und das vorherige (falls vorhanden) erneut angezeigt. Beachten Sie, dass in diesem Fall DialogFragment dafür sorgt, dass die Transaktion des Dialogs getrennt von dieser gelöscht wird.

Für meine Bedürfnisse habe ich es geändert in:

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

MyDialogFragment fragment = new MyDialogFragment();
fragment.show(manager, TAG);

0

Rufen Sie einfach entlassen () aus dem Fragment auf, das Sie schließen möchten.

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

0

Ich stellte fest, dass <fragment>das Dialogfragment mit dem dismiss()Befehl nicht geschlossen wurde, wenn mein Fragment im Navigationsdiagramm mit einem Tag definiert wurde (für ein Vollbild-Dialogfragment) . Stattdessen musste ich den Backstack platzen lassen:

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

Wenn jedoch dasselbe Dialogfragment im Navigationsdiagramm mit einem <dialog>Tag definiert wurde, dismiss()funktioniert dies einwandfrei .


0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}

0

Wenn Sie zu den anderen Antworten hinzufügen , wird bei einem DialogFragmentVollbildaufruf dismiss()das DialogFragment nicht aus dem Fragment-Backstack entfernt. Eine Problemumgehung besteht darin, onBackPressed()die übergeordnete Aktivität aufzurufen .

Etwas wie das:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.