Jak poprawnie odrzucić DialogFragment?


121

Dokumentacja mówi tak dla dismiss()metody z Dialogklasy:

Zamknij to okno dialogowe, usuwając je z ekranu. Tę metodę można bezpiecznie wywołać z dowolnego wątku. Zauważ, że nie powinieneś nadpisywać tej metody, aby wykonać czyszczenie, gdy okno dialogowe jest zamknięte, zamiast tego zaimplementuj ją w onStop().

W moim kodzie wszystko, co robię, to getDialog().dismiss()odwoływanie się. Ale nie robię nic innego ani nawet nie używam onStop(). Więc pytam dokładnie, jak poprawnie odrzucić a, DialogFragmentaby uniknąć wycieków pamięci itp.

Odpowiedzi:


197

tl; dr: poprawnym sposobem zamknięcia a DialogFragmentjest użycie dismiss() bezpośrednio w DialogFragment .


Szczegóły : dokumentacja stanów DialogFragment

Sterowanie oknem dialogowym (decydowanie, kiedy je pokazać, ukryć, zamknąć) powinno odbywać się za pośrednictwem interfejsu API tutaj, a nie za pomocą bezpośrednich wywołań w oknie dialogowym.

Dlatego nie powinieneś używać getDialog().dismiss(), ponieważ wywołałoby dismiss() to okno dialogowe . Zamiast tego należy użyć samej dismiss()metody DialogFragment:

publiczne void odrzucić ()

Odrzuć fragment i jego dialog. Jeśli fragment został dodany do tylnego stosu, wszystkie stany tylnego stosu do tego wpisu włącznie zostaną usunięte. W przeciwnym razie zostanie zatwierdzona nowa transakcja w celu usunięcia fragmentu.

Jak widać, zajmuje się to nie tylko zamknięciem okna dialogowego, ale także obsługą transakcji fragmentowych zaangażowanych w proces.

Musisz użyć tylko onStopwtedy, gdy jawnie utworzyłeś jakiekolwiek zasoby, które wymagają ręcznego czyszczenia (zamykanie plików, zamykanie kursorów itp.). Nawet wtedy zastąpiłbym onStopDialogFragment zamiast onStoppodstawowego Dialog.


1
@ScootrNova: Nie powinno, prawdopodobnie gdzie indziej masz błąd. Jak tworzysz ten fragment?
Heinzi

protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Przepraszam za paskudną jedną wkładkę! Ale tak, możesz mieć rację, więc na razie napisałem inny sposób na zamknięcie moich DialogFragments. Sposób, w jaki je odrzucałem za pomocą metody dismiss (), polegał na znalezieniu fragmentu po tagu, a następnie uruchomieniu na nim disciss (), jeśli nie był pusty. Aha i tak, newumieszczam fragment tuż przed przekazaniem go do tej metody.
Charles Madere

2
@ScootrNova: Hmm, nie widzę w tym nic złego - z drugiej strony nigdy nie korzystałem z biblioteki kompatybilności, więc nie mogę być tego pewien. Może warto byłoby stworzyć minimalny, samodzielny przykład i zacząć nowe pytanie na ten temat.
Heinzi

@CharlesMadere w tamtych czasach, czy znalazłeś rozwiązanie?
JCarlosR

Przepraszam @JCarlos, to było lata temu, nie jestem pewien.
Charles Madere

76

Myślę, że lepszym sposobem na zamknięcie DialogFragmentjest:

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

W ten sposób nie musisz mieć odniesienia do pliku DialogFragmenti możesz go zamknąć z dowolnego miejsca.


7

Dlaczego nie spróbujesz użyć tylko tego kodu:

dismiss();

Jeśli chcesz samodzielnie odrzucić fragment okna dialogowego. Możesz po prostu umieścić ten kod wewnątrz fragmentu okna dialogowego, w którym chcesz zamknąć okno dialogowe.

Na przykład:

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

Spowoduje to zamknięcie ostatniego fragmentu okna dialogowego, który jest wyświetlany na ekranie.

Mam nadzieję, że to pomoże.


nie działa cały czas
Mahmoud Heretani

5

Głosowałem za odpowiedzią Terela. Chciałem tylko opublikować to dla wszystkich użytkowników Kotlin:

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

Prosty kod działa ciężko. Dzięki za aktualizację!
Ayush Katuwal

4

Odpowiedź Kotlin Version of Terel

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

1

Należy odrzucić cię Dialogw onPause()tak zastąpić.

Również przed zamknięciem możesz sprawdzić nulli wyświetla się jak poniżej fragment:

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

napisał już, że robi odciśniecie () i chodzi o DialogFragment.
Paresh Mayani

Myślę, że to działa zarówno dla Dialog, jak i DialogFragments @PareshMayani
Venky

2
Uważam, że @PareshMayani ma rację Venky. Samouczek na DialogFragmentGoogle w ogóle nie pokazuje onPause()używanej metody. Ale myślę, że rozumiem, co robisz. O co chodzi, jeśli użytkownik nie dzwoni onPause(). To wtedy, gdy system wie, że fragment jest wywoływany. A kiedy, powiedzmy, że użytkownik anuluje subskrypcję. Jaki jest lepszy sposób na zamknięcie tego w takim przypadku?
Andy

1

W innych odpowiedziach znajdują się odniesienia do oficjalnych dokumentów ( DialogFragment Reference ), ale nie ma wzmianki o podanym tam przykładzie:

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

Spowoduje to usunięcie aktualnie wyświetlanego okna dialogowego, utworzenie nowego DialogFragment z argumentem i wyświetlenie go jako nowego stanu na tylnym stosie. Po wyskakiwaniu transakcji bieżący DialogFragment i jego okno dialogowe zostaną zniszczone, a poprzednia (jeśli istnieje) zostanie ponownie pokazana. Zauważ, że w tym przypadku DialogFragment zajmie się popping transakcją Dialogu, która jest odrzucana oddzielnie od niej.

Na moje potrzeby zmieniłem to na:

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

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

1

Dodanie do innych odpowiedzi, gdy DialogFragmentwywołanie jest pełnoekranowe dismiss(), nie spowoduje wyskoczenia DialogFragment z zaplecza fragmentu. Sposób obejścia problemu polega na wywołaniu onBackPressed()działania rodzica.

Coś takiego:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}

Oszczędzaj dzień, wielkie dzięki
Mahmoud Heretani

0

Po prostu wywołaj odrzucenie () z fragmentu, który chcesz odrzucić.

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

0

Zauważyłem, że gdy mój fragment został zdefiniowany na wykresie nawigacyjnym za pomocą <fragment>tagu (dla pełnoekranowego fragmentu dialogowego), fragment okna dialogowego nie został usunięty za pomocą dismiss()polecenia. Zamiast tego musiałem zdjąć tylny stos:

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

Jeśli jednak ten sam fragment okna dialogowego został zdefiniowany na wykresie nawigacyjnym ze <dialog>znacznikiem, dismiss()działa dobrze.


0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.