DialogFragment and onDismiss
Asked Answered
A

12

78

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?

Align answered 21/5, 2014 at 14:22 Comment(4)
you can use boolean value before dimissing the dialog and use that boolean value to notify activitySelfdrive
Okay, how would I notify the activity?Align
intially set boolean value to false and before dismissing dialog set boolean value to true and to notify activty use boolean value to check whether value is true or falseSelfdrive
I know it's been a while but have you forgotten to accept the answer?Oil
O
117

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

}
Oil answered 21/5, 2014 at 14:27 Comment(7)
@ashishduh the op is using a DialogFragment, not a dialogBoehmenism
You can't set dismiss listener to a dialog owned by a DialogFragment, The solution provided by Doctoror Drive is the right one. Just don't forget to call super.onDismiss(dialog) - things will get broken otherwise.Pollinosis
@ashishduh I suggest you remove your comment. You made me look up the documentationWiltz
who is Doctoror Drive?Narton
who is extends AcitivityNarton
@lukecross my previous user name was Doctoror Drive.Oil
In case this didn't work for anyone, make sure you're displaying your fragment using myFragment.show(fragmentManager, "TAG");.Asternal
C
47

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.

Confuse answered 26/1, 2017 at 10:33 Comment(7)
@Simas: Can you elaborate on "doesn't work"? Is there a compile error? a runtime problem?Reach
@Reach as far as I remember calling fm.executePendingTransactions(); didn't protect from an NPE as is said on this answer.Horsefly
Seems clean solution, but on screen rotation, it will call onDismiss callback, which may trigger unwanted logic, assuming that this logic should be run when user makes some actions in the dialog after which dismiss() is calledProfusive
Works for me perfectly.Oarlock
don't forget to call dialog.dismiss() inside onDismiss(DialogInterface dialogInterface) because dialog will reappear when you switch apps and come back...Encarnalize
It's noted on official documentation that instead of calling show() then executePendingTransactions(), it would be more concise to just call idiomatic showNow().Underprivileged
and dismiss listener set like this on the dialog doesn't seem to be called when the dialogfragment itself is dismiss()ed, which is the recommended thing to do.Underprivileged
E
15

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);
Ellipticity answered 17/5, 2017 at 15:0 Comment(0)
C
8

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(...); 
}
Calabar answered 18/8, 2015 at 8:54 Comment(3)
I was doing this and thought I was clever, but this is dangerous. If the framework decides to recreate the dialog (due to a configuration change or screen rotation), it will use the empty dialog fragment constructor and the onDismissListener will not be set.Parsec
Yes you're right. Add this in onCreate of your activity MyDialogFragment myDialogFragment = getFragmentManager().findFragmentByTag("MyDialogFragment"); if(myDialogFragment != null) { myDialogFragment.setOnDismissListener(...); }Calabar
And of course add the same tag in your dialogFragment.show(getFragmentManager(), "MyDialogFragment")Calabar
F
4
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);
        });
Fibrinolysis answered 23/8, 2018 at 15:15 Comment(0)
D
2

Solution using kotlin and additional interface. (an example for a fragment will be shown here, but with a few changes it will work in an activity as well)

First you need to create an interface (the set of parameters can be any):

interface DialogCloseListener {
    fun handleDialogClose(dialog: DialogInterface)
}

Then implement this interface in the fragment that calls the DailogFragment:

class YourParentFragment: Fragment(), DialogCloseListener {
override fun handleDialogClose(dialog: DialogInterface) {
// do something
}
}

Now go to your DialogFragment. Implement the onDismiss method. In it, check if the parent fragment implements your interface, call your method, passing the necessary parameters there:

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        if(parentFragment is DialogCloseListener){
            (parentFragment as DialogCloseListener).handleDialogClose(dialog)
        }
    }

I think that this way is good because you can track a specific close event (by passing a certain parameter to the method), for example, canceling an order, and somehow handle it.

Driskell answered 22/6, 2022 at 14:54 Comment(0)
S
1

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!

Strahan answered 16/5, 2018 at 15:29 Comment(0)
A
1

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();
    }
}
Alexi answered 24/1, 2019 at 19:51 Comment(0)
L
1

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

Loosing answered 12/3, 2020 at 18:3 Comment(0)
C
1

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.
    }
}
Cooperate answered 1/11, 2021 at 19:59 Comment(0)
M
0

Try this

dialog.setOnDismissListener {
            Log.e("example","example")
        }
       

Have Fun!

Mattiematting answered 4/7, 2022 at 16:3 Comment(0)
P
0

Kotlin example.

In your dialog:

btCancel.setOnClickListener {
    val bundle = Bundle().apply {
        putBoolean(CANCEL_KEY, true)
    }
            
    requireActivity().supportFragmentManager.setFragmentResult(
        CANCEL_KEY, bundle
    )

    dismiss()
}

In your fragment:

const val CANCEL_KEY = "cancel_key"
const val YOUR_DIALOG_TAG = "your_dialog"

//...

private fun showDialog() {
    val dialog = YourDialog()
    dialog.show(supportFragmentManager, YOUR_DIALOG_TAG)

    supportFragmentManager.setFragmentResultListener(CANCEL_KEY, 
        viewLifecycleOwner) { _, _ ->
       // reaction on cancel
    }
}
Parental answered 23/11, 2023 at 7:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.