DialogFragment and onDismiss

AndroidAndroid Dialogfragment

Android Problem Overview


I am using a DialogFragment, which I am showing like this from an Activity:

DialogFragmentImage dialog = DialogFragmentImage.newInstance(createBitmap());
dialog.onDismiss(dialog);.onDismiss(this);	    	
dialog.show(getFragmentManager(), "DialogFragmentImage");

I would like to check when the DialogFragment was dismissed (for example when the back button was pressed), but in my Activity. How can I do that? How can I "tell" my activity that the DialogFragment has been dismissed?

Android Solutions


Solution 1 - Android

Make your Activity implement OnDismissListener

public final class YourActivity extends Activity implements DialogInterface.OnDismissListener {

    @Override
    public void onDismiss(final DialogInterface dialog) {
        //Fragment dialog had been dismissed
    }

}

DialogFragment already implements OnDismissListener, just override the method and call the Activity.

public final class DialogFragmentImage extends DialogFragment {

    ///blah blah

    @Override
    public void onDismiss(final DialogInterface dialog) {
        super.onDismiss(dialog);
        final Activity activity = getActivity();
        if (activity instanceof DialogInterface.OnDismissListener) {
            ((DialogInterface.OnDismissListener) activity).onDismiss(dialog);
        }
    }

}

If you're starting the dialog from a fragment using the childFragment manager (API>=17), you can use getParentFragment to talk to the onDismissListener on the parent fragment.:

public final class DialogFragmentImage extends DialogFragment {

    ///blah blah

    @Override
    public void onDismiss(final DialogInterface dialog) {
        super.onDismiss(dialog);
        Fragment parentFragment = getParentFragment();
        if (parentFragment instanceof DialogInterface.OnDismissListener) {
            ((DialogInterface.OnDismissListener) parentFragment).onDismiss(dialog);
        } 
    }

}

Solution 2 - Android

Here is my answer. It's a bit late but it's maybe benefit someone passing by.

FragmentManager fm = getFragmentManager();

YourDialogFragment dialog = new YourDialogFragment();
dialog.show(fm,"MyDialog");

fm.executePendingTransactions();
dialog.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialogInterface) {
                       //do whatever you want when dialog is dismissed
                    }
                });

We need to call

fm.executePendingTransactions(); 

To make sure that FragmentTransaction work has been performed. Otherwise NullPointerException can occur when calling setOnDismissListener().

Sorry if there is any mistake. Hope this help.

Solution 3 - Android

This is an old issue but I found no solution I am happy with. I don't like passing any Listeners to my DialogFragment or set a TargetFragment, because that may break on orientation change. What do you think about this?

        MyDialog d = new MyDialog();
        d.show(fragmentManager, "tag");
        fragmentManager.registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
    	    @Override
			public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
				super.onFragmentViewDestroyed(fm, f);
				//do sth      
        fragmentManager.unregisterFragmentLifecycleCallbacks(this);
    			}
    		}, false);

Solution 4 - Android

Alternative answer, if you don't have access to the methode onDismiss of activity.

//DIALOGFRAGMENT
//Create interface in your DialogFragment (or a new file)
public interface OnDismissListener {
   void onDismiss(MyDialogFragment myDialogFragment);
}
//create Pointer and setter to it
private OnDismissListener onDismissListener;
public void setDissmissListener(DissmissListener dissmissListener) {
   this.dissmissListener = dissmissListener;
}
//Call it on the dialogFragment onDissmiss
@Override
public void onDismiss(DialogInterface dialog) {
   super.onDismiss(dialog);
    
   if (onDismissListener != null) {
      onDismissListener.onDismiss(this);
   }
}
    
//OTHER CLASS, start fragment where you want
MyDialogFragment df = new MyDialogFragment();
df.setOnDismissListener(new MyDialogFragment.OnDismissListener() {
   @Override
   public void onDismiss(MyDialogFragment myDialogFragment) {
      //Call when MyDialogFragment close
   }
});
df.show(activity.getFragmentManager(), "myDialogFragment");

edit : if system need to recreate DialogFragment: you can find it with

MyDialogFragment myDialogFragment = getFragmentManager().findFragmentByTag("MyDialogFragment"); 
if(myDialogFragment != null) { 
   myDialogFragment.setOnDismissListener(...); 
}

Solution 5 - Android

public class OpcoesProdutoDialogo extends DialogFragment{
    private DialogInterface.OnDismissListener onDismissOuvinte;
.
.
.

@Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if(onDismissOuvinte!=null)
            onDismissOuvinte.onDismiss(dialog);
    }

    public void setOnDismissListener(@Nullable DialogInterface.OnDismissListener listener) {
        this.onDismissOuvinte = listener;
    }
}

and in call

OpcoesProdutoDialogo opcProduto = OpcoesProdutoDialogo.criar(itemPedido);
        opcProduto.show(getFragmentManager(), "opc_produto_editar");
        opcProduto.setOnDismissListener(d->{
            adapterItens.notifyItemChanged(posicao);
        });

Solution 6 - Android

If you don't like the solution of @yaroslav-mytkalyk, in which the fragment needs to cast the activity / parent fragment, here's another one:

Here's the idea:

  1. Expose a listener in your fragment, DialogFragmentImage.
  2. Implement the listener in your activity and pass it to the fragment when creating it. Make sure to use a tag as well in order to be able to find the fragment later (read below).
  3. In onStop(), remove the listener in order not to leak the activity if it's destroyed. This will happen when the screen is rotated, as the activity will be re-created.
  4. In onResume(), check if the fragment exists and if yes, re-add the listener.

Expose a listener from your fragment:

class MyFragment extends DialogFragment {

    public interface OnDismissListener {
        void dismissed();
    }

    @Nullable
    private OnDismissListener onDismissListener;

    public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
        this.onDismissListener = onDismissListener;
    }

    /*
    If you are calling dismiss() or dismissAllowingStateLoss() manually,
    don't forget to call:
    if (onDismissListener != null) {
        onDismissListener.dismissed();
    }

    Otherwise, override them and call it there.
    */
}

And this is how your activity should look like:

class MyActivity extends AppCompatActivity {

    private static final String MY_FRAGMENT_TAG = "my_fragment";

    private MyFragment.OnDismissListener myFragmentListener = () -> {

        // ...
    };

    /**
     * Shows the fragment. Note that:
     * 1. We pass a tag to `show()`.
     * 2. We set the listener on the fragment.
     */
    private void showFragment() {

        MyFragment fragment = new MyFragment();
        fragment.show(getSupportFragmentManager(), MY_FRAGMENT_TAG);
        fragment.setOnDismissListener(myFragmentListener);
    }

    @Override
    protected void onStart() {

        super.onStart();

        // Restore the listener that we may have removed in `onStop()`.
        @Nullable MyFragment myFragment =  (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGMENT_TAG);
        if (myFragment != null) {
            myFragment.setOnDismissListener(myFragmentListener);
        }
    }

    @Override
    protected void onStop() {

        // If the fragment is currently shown, remove the listener so that the activity is not leaked when e.g. the screen is rotated and it's re-created.
        @Nullable MyFragment myFragment =  (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGMENT_TAG);
        if (myFragment != null) {
            myFragment.setOnDismissListener(null);
        }

        super.onStop();
    }
}

Solution 7 - Android

Care : all example aren't correct because your fragment should have a no-arg constructor !

Working code with back gesture and close button in the fragment itself. I removed useless code stuff like getting arg in onCreate etc.

Important : onDismiss is also call when orientation change so as a result you should check if the context is not null in your callback (or using other stuff).

public class MyDialogFragment extends DialogFragment {
    
	public static String TAG = "MyFragment";

	public interface ConfirmDialogCompliant {
		void doOkConfirmClick();
	}

	
	public MyFragment(){
		super();
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
							 Bundle savedInstanceState) {
		// Inflate the layout for this fragment
		View rootView = inflater.inflate(R.layout.fragment_layout, container, false);

		((ImageButton) rootView.findViewById(R.id.btn_close)).setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				// close fragment
				dismiss();
			}
		});
		return rootView;
	}

	@Override
	public void onDismiss(@NonNull DialogInterface dialog) {
		super.onDismiss(dialog);
		// notify
		if(caller != null)
		   caller.doOkConfirmClick();
		}
	}

	public void setCallback(ConfirmDialogCompliant caller) {
		this.caller = caller;
	}

	public static MyDialogFragment newInstance(String id) {
		MyDialogFragment f = new MyDialogFragment();

		// Supply num input as an argument.
		Bundle args = new Bundle();
		args.putString("YOU_KEY", id);
		f.setArguments(args);

		return f;
	}
}

And now how to call it from parent.

MyDialogFragment.ConfirmDialogCompliant callback = new MyDialogFragment.ConfirmDialogCompliant() {

            @Override
            public void doOkConfirmClick() {
                // context can be null, avoid NPE
                if(getContext() != null){

                }

            }

        };

    MyDialogFragment fragment = MyDialogFragment.newInstance("item");
    fragment.setCallback(callback);
    fragment.show(ft, MyDialogFragment.TAG);
        new MyDialogFragment(callback, item);

    fragment.show(getActivity().getSupportFragmentManager(), MyDialogFragment.TAG);
   

Additionnal source : https://developer.android.com/reference/android/app/DialogFragment

Solution 8 - Android

You can subclass DialogFragment and provide your own listener that is going to be called and in onCancel.

var onDismissListener: (() -> Unit)? = null

For the ones not familiar with Kotlin this is just an anonymous interface that saves boilerplate iterface in Java. Use a field and a setter in Java.

And then in onCancel

    override fun onCancel(dialog: DialogInterface?) {
    super.onCancel(dialog)
    onDismissListener?.invoke()
}

Have fun!

Solution 9 - Android

Kotlin Answer

private fun showMyCustomDialog() {

    // Show.
    MyCustomDialogFragment().show(fm, "MyCustomDialogFragment")
    
    // Set pending transactions.
    fm.executePendingTransactions()
    
    // Listen dialog closing.
    MyCustomDialogFragment().dialog?.setOnDismissListener { 
        
        // You can do you job when it closed.
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiondeimos1988View Question on Stackoverflow
Solution 1 - AndroidYaroslav MytkalykView Answer on Stackoverflow
Solution 2 - AndroidBoonya KitpitakView Answer on Stackoverflow
Solution 3 - AndroidKaskasiView Answer on Stackoverflow
Solution 4 - AndroidAnthoneView Answer on Stackoverflow
Solution 5 - Androidd3roch4View Answer on Stackoverflow
Solution 6 - AndroidMinas MinaView Answer on Stackoverflow
Solution 7 - AndroidZharView Answer on Stackoverflow
Solution 8 - AndroidPreslav PetkovView Answer on Stackoverflow
Solution 9 - AndroidNamelessView Answer on Stackoverflow