Come chiudere correttamente un DialogFragment?


121

I documenti dicono questo per il dismiss()metodo della Dialogclasse:

Chiudi questa finestra di dialogo, rimuovendola dallo schermo. Questo metodo può essere richiamato in modo sicuro da qualsiasi thread. Nota che non dovresti sovrascrivere questo metodo per eseguire la pulizia quando la finestra di dialogo viene chiusa, ma implementalo in onStop().

Nel mio codice, tutto ciò che faccio è chiamare getDialog().dismiss()per ignorarlo. Ma non sto facendo nient'altro e nemmeno sto usando onStop(). Quindi sto chiedendo esattamente come chiudere correttamente un DialogFragmentper evitare perdite di memoria, ecc.

Risposte:


197

tl; dr: il modo corretto per chiudere a DialogFragmentè usare dismiss() direttamente sul DialogFragment .


Dettagli : la documentazione degli stati DialogFragment

Il controllo della finestra di dialogo (decidere quando mostrarla, nasconderla, chiuderla) dovrebbe essere eseguita tramite l'API qui, non con chiamate dirette nella finestra di dialogo.

Pertanto, non dovresti usare getDialog().dismiss(), poiché ciò invocerebbe dismiss() nella finestra di dialogo . Invece, dovresti usare il dismiss()metodo del DialogFragment stesso:

public void dismiss ()

Elimina il frammento e la relativa finestra di dialogo. Se il frammento è stato aggiunto allo stack posteriore, verrà estratto tutto lo stato dello stack precedente fino a questa voce inclusa. In caso contrario, verrà eseguito il commit di una nuova transazione per rimuovere il frammento.

Come puoi vedere, questo si occupa non solo di chiudere la finestra di dialogo ma anche di gestire le transazioni dei frammenti coinvolte nel processo.

È necessario utilizzare solo onStopse sono state create esplicitamente risorse che richiedono la pulizia manuale (chiusura di file, chiusura di cursori, ecc.). Anche in questo caso, sovrascriverei onStopil DialogFragment anziché onStopil Dialog sottostante.


1
@ScootrNova: Non dovrebbe, probabilmente hai un bug altrove. Come stai creando il frammento?
Heinzi

protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Ci scusiamo per la brutta fodera! Ma sì, potresti avere ragione, quindi per il momento ho scritto un altro modo per chiudere i miei DialogFragments. Il modo in cui li stavo ignorando utilizzando il metodo dismiss () era solo trovare il frammento per tag e quindi eseguire dismiss () su di esso se non era null. Oh e sì, sto newinserendo il frammento subito prima di passarlo a quel metodo.
Charles Madere

2
@ScootrNova: Hmm, non vedo niente di sbagliato in questo - d'altra parte, non ho mai usato la libreria di compatibilità, quindi non posso esserne sicuro. Forse potrebbe avere senso creare un esempio minimale e autonomo e iniziare una nuova domanda su questo.
Heinzi

@CharlesMadere in quei giorni, hai trovato una soluzione?
JCarlosR

Mi dispiace @JCarlos, questo è stato anni fa, non sono sicuro.
Charles Madere

76

Penso che un modo migliore per chiudere un DialogFragmentsia questo:

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

In questo modo non devi tenere un riferimento a DialogFragmente puoi chiuderlo ovunque.


7

Perché non provi a utilizzare solo questo codice:

dismiss();

Se vuoi chiudere il frammento di dialogo da solo. Puoi semplicemente inserire questo codice all'interno del frammento di dialogo in cui desideri chiudere la finestra di dialogo.

Per esempio:

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

Questo chiuderà il recente frammento di dialogo mostrato sullo schermo.

Spero che ti aiuti.


non funziona sempre
Mahmoud Heretani il

5

Ho dato un voto positivo alla risposta di Terel. Volevo solo pubblicare questo per tutti gli utenti di Kotlin:

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

Il codice semplice funziona sodo, grazie per il compagno di aggiornamento !!
Ayush Katuwal

4

Kotlin Versione di Terel risposta

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

1

Dovresti licenziarti Dialogin onPause()modo da ignorarlo.

Inoltre, prima di ignorare, puoi verificare nulle viene visualizzato come sotto lo snippet:

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

ha già scritto che sta facendo dismiss () e riguarda DialogFragment.
Paresh Mayani

Penso che questo funzioni sia per Dialog che per DialogFragments @PareshMayani
Venky

2
Credo che @PareshMayani abbia ragione Venky. Il tutorial DialogFragmentdi Google non mostra affatto il onPause()metodo utilizzato. Ma credo di vedere cosa stai facendo. Qual è il punto se l'utente non sta chiamando onPause(). Quello è quando il sistema sa che il frammento è stato richiamato. E quando, ad esempio, un utente annulla. Qual è il modo migliore per chiuderlo in quel caso?
Andy

1

Ci sono riferimenti ai documenti ufficiali ( DialogFragment Reference ) in altre risposte, ma nessuna menzione dell'esempio fornito qui:

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

Ciò rimuove qualsiasi finestra di dialogo attualmente visualizzata, crea un nuovo DialogFragment con un argomento e lo mostra come un nuovo stato nello stack precedente. Quando la transazione viene estratta, il DialogFragment corrente e il relativo Dialog verranno distrutti e il precedente (se presente) verrà mostrato nuovamente. Si noti che in questo caso DialogFragment si prenderà cura di far scoppiare la transazione del Dialog viene congedato separatamente da esso.

Per le mie esigenze l'ho cambiato 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);

1

Aggiungendo alle altre risposte, quando si ha una DialogFragmentchiamata a schermo intero dismiss()non verrà visualizzato il DialogFragment dal backstack del frammento. Una soluzione alternativa è chiamare onBackPressed()l'attività genitore.

Qualcosa come questo:

CustomDialogFragment.kt

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

Salva la giornata, grazie mille
Mahmoud Heretani

0

Chiama semplicemente dismiss () dal frammento che vuoi eliminare.

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

0

Ho scoperto che quando il mio frammento è stato definito nel grafico di navigazione con un <fragment>tag (per un dialogfragment a schermo intero), il dialogfragment non si chiudeva con il dismiss()comando. Invece, ho dovuto aprire lo stack posteriore:

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

Tuttavia, se lo stesso frammento di dialogo è stato definito nel grafico di navigazione con un <dialog>tag, dismiss()funziona bene.


0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.