¿Cómo descartar correctamente un DialogFragment?

121

Los documentos dicen esto para el dismiss()método de la Dialogclase:

Descarte este diálogo, eliminándolo de la pantalla. Este método se puede invocar de forma segura desde cualquier hilo. Tenga en cuenta que no debe anular este método para realizar la limpieza cuando se cierra el cuadro de diálogo, sino implementarlo en onStop().

En mi código, todo lo que hago es llamar getDialog().dismiss()para descartarlo. Pero no estoy haciendo nada más ni siquiera consumiendo onStop(). Así que pregunto exactamente cómo descartar correctamente un DialogFragmentpara evitar pérdidas de memoria, etc.

Andy
fuente

Respuestas:

197

tl; dr: La forma correcta de cerrar un DialogFragmentes usar dismiss() directamente en DialogFragment .


Detalles : la documentación de los estados de DialogFragment

El control del cuadro de diálogo (decidir cuándo mostrarlo, ocultarlo, descartarlo) debe hacerse a través de la API aquí, no con llamadas directas al cuadro de diálogo.

Por lo tanto, no debe usarlo getDialog().dismiss(), ya que lo invocaría dismiss() en el diálogo . En su lugar, debe utilizar el dismiss()método del propio DialogFragment:

descarte público vacío ()

Descarte el fragmento y su diálogo. Si el fragmento se agregó a la pila de actividades, se mostrarán todos los estados de la pila hasta esta entrada inclusive. De lo contrario, se confirmará una nueva transacción para eliminar el fragmento.

Como puede ver, esto se encarga no solo de cerrar el diálogo sino también de manejar las transacciones de fragmentos involucradas en el proceso.

Solo necesita usar onStopsi creó explícitamente cualquier recurso que requiera limpieza manual (cerrar archivos, cerrar cursores, etc.). Incluso entonces, anularía onStopel DialogFragment en lugar onStopdel Dialog subyacente.

Heinzi
fuente
1
@ScootrNova: No debería, probablemente tengas un error en otro lugar. ¿Cómo estás creando el fragmento?
Heinzi
protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} ¡Perdón por el desagradable delineador! Pero sí, podrías tener razón, así que por el momento he escrito otra forma de cerrar mis DialogFragments. La forma en que los descartaba usando el método despedir () era simplemente encontrar el fragmento por etiqueta y luego ejecutar despedir () en él si no era nulo. Ah, y sí, estoy newgrabando el fragmento justo antes de pasarlo a ese método.
Charles Madere
2
@ScootrNova: Hmm, no veo nada malo en eso; por otro lado, nunca he usado la biblioteca de compatibilidad, así que no puedo estar seguro de eso. Tal vez tenga sentido crear un ejemplo mínimo y autónomo y comenzar una nueva pregunta sobre eso.
Heinzi
@CharlesMadere en esos días, ¿encontraste una solución?
JCarlosR
Lo siento @JCarlos, esto fue hace años, no estoy seguro.
Charles Madere
76

Creo que una mejor manera de cerrar una DialogFragmentes esta:

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

De esta manera, no es necesario que mantenga una referencia al DialogFragmenty puede cerrarlo desde cualquier lugar.

Terel
fuente
7

¿Por qué no intentas usar solo este código?

dismiss();

Si desea descartar el fragmento de diálogo por sí solo. Simplemente puede poner este código dentro del fragmento de diálogo donde desea cerrar el diálogo.

Por ejemplo:

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

Esto cerrará el fragmento de diálogo reciente que se muestra en la pantalla.

Espero que te ayude.

Shiva Tiwari
fuente
no funciona todo el tiempo
Mahmoud Heretani
5

Di un voto positivo a la respuesta de Terel. Solo quería publicar esto para cualquier usuario de Kotlin:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}
Justin Morris
fuente
El código simple funciona duro, ¡Gracias por la actualización, amigo!
Ayush Katuwal
4

Respuesta de Kotlin Versión de Terel

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

Deberías despedirte DialogenonPause() lo que anularlo.

Además, antes de descartar, puede verificar nully se muestra como el siguiente fragmento:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}
Venky
fuente
ya ha escrito que está haciendo desechar () y se trata de DialogFragment.
Paresh Mayani
Creo que esto funciona tanto para Dialog como para DialogFragments @PareshMayani
Venky
2
Creo que @PareshMayani tiene razón, Venky. El tutorial DialogFragmentde Google no muestra en absoluto el onPause()método que se está utilizando. Pero creo que veo lo que estás haciendo. Sin embargo, cuál es el punto si el usuario no está llamando onPause(). Es entonces cuando el sistema sabe que el fragmento está siendo retirado. ¿Qué pasa cuando, digamos, un usuario cancela? ¿Cuál es una mejor manera de cerrarlo en ese caso?
Andy
1

Hay referencias a los documentos oficiales ( DialogFragment Reference ) en otras respuestas, pero no se menciona el ejemplo que se da allí:

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

Esto elimina cualquier diálogo mostrado actualmente, crea un nuevo DialogFragment con un argumento y lo muestra como un nuevo estado en la pila de actividades. Cuando se abre la transacción, el DialogFragment actual y su Dialog se destruirán, y se volverá a mostrar el anterior (si lo hay). Tenga en cuenta que en este caso DialogFragment se encargará de hacer estallar la transacción del Diálogo que se descarta por separado.

Para mis necesidades lo cambié a:

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
fuente
1

Agregando a las otras respuestas, cuando se tiene una DialogFragmentllamada a pantalla completa dismiss(), no aparecerá el DialogFragment de la pila de fragmentos. Una solución alternativa es llamaronBackPressed() a la actividad principal.

Algo como esto:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}
mikehc
fuente
Salva el día, muchas gracias
Mahmoud Heretani
0

Simplemente llame a descartar () desde el fragmento que desea descartar.

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

Descubrí que cuando mi fragmento se definía en el gráfico de navegación con una <fragment>etiqueta (para un fragmento de diálogo de pantalla completa), el fragmento de diálogo no se descartaba con el dismiss()comando. En cambio, tuve que hacer estallar la pila trasera:

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

Sin embargo, si el mismo fragmento de diálogo se definió en el gráfico de navegación con una <dialog>etiqueta, dismiss()funciona bien.

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