27
votes

I want to launch a dialog with a custom layout, which I've implemented via a DialogFragment. (I basically just changed onCreateView() and added button handlers). The dialog lets the user quickly change an important setting.

This dialog will be launched from several different activities. The different activities don't have much in common, except that they need to refresh after the user makes a change to the setting. They don't need to get any information from the dialog; they merely need to know when it's closed (dismissed).

What I've Tried

I tried having the activity refresh in onResume(), but launching and dismissing a dialog never seems to call this method. (So I'm not sure why it even exists, but that's probably a topic for another question.)

Next, I tried adding a DialogInterface.OnDismissListener to the dialog:

public static void showMyDialog(OnDismissListener listener, Activity activity)
{
    DialogFragment fragment = new MyDialogFragment();
    fragment.show(activity.getFragmentManager(), "date");
    activity.getFragmentManager().executePendingTransactions();//A
    fragment.getDialog().setOnDismissListener(listener);//B
}

When I originally left out the line A, I got a NullPointerException on line B because the dialog is null at that point. Following the advice of this SO answer, I put in the call to executePendingTransaction(). This causes an IllegalStateException on line B, with the message "OnDismissListener is already taken by DialogFragment and cannot be replaced." I also tried putting setOnDismissListener() before the call to show(), but that always caused a NullPointerException.

I then read this other SO answer, which says the original asker was "calling getDialog() too early in the DialogFragment's life cycle." So I tried adding a constructor to my DialogFragment:

public MyDialogFragment(SomeCallback illTakeAnythingICanGet)
{
    //I'll store the callback here and call it later
}

Unfortunately, adding a constructor made Android Lint freak out with a fatal warning, and when I looked it up, I found a comment in this question that seems to say this approach will make it impossible to deal with the user rotating the screen while the dialog is open.

The Question

How can an activity figure out when a DialogFragment has closed (been dismissed) in a way that won't break my app if the user rotates the screen? Should I be using something else besides a DialogFragment?

3
Is it necessary Activity does the work and tries to figure out the state of the dialog? It might be easier to send notification from DialogFragment to its owner Activity when it gets closed instead. I.e if SomeCallback is an interface with callback method , implement it in Activities that need to get notified. In DialogFragment you can override onDismiss(DialogInterface) to check if getActivity() returns an instance of SomeCallback - and if it is - call the interface method.harism
I just made an interface from a fragment it's the same thing @harism is talking about. stackoverflow.com/questions/24149696/…danny117
@harism makes sense; I'll try this out when I get a chance.Impatient Dev
harism's solotion worked for me. I don't have the rep to post it as an answer yet.Impatient Dev

3 Answers

35
votes

This is just a longer explanation of harism's comment in case anyone else has the same problem I did.

You can accomplish what I wanted by creating an interface like this:

public interface MyDialogCloseListener
{
    public void handleDialogClose(DialogInterface dialog);//or whatever args you want
}

Have the activity that launches your dialog (DialogFragment) implement this interface. Then give that DialogFragment the following method:

public void onDismiss(DialogInterface dialog)
{
    Activity activity = getActivity();
    if(activity instanceof MyDialogCloseListener)
        ((MyDialogCloseListener)activity).handleDialogClose(dialog);
}
18
votes

More explanatory code for someone to do the same.

Create the interface as:

package com.example.dialoglistener;
import android.content.DialogInterface;

public interface MyDialogCloseListener {
    public void handleDialogClose(DialogInterface dialog);
}

Implement the interface in activity as:

MyDialogCloseListener closeListener = new MyDialogCloseListener() {
        @Override
        public void handleDialogClose(DialogInterface dialog) {                                     
            //do here whatever you want to do on Dialog dismiss
        }
};

Write a DismissListener in DialogFragement as

public void DismissListener(MyDialogCloseListener closeListener) {
        this.closeListener = closeListener;
}

call DismissListener from your activity as:

dialogFragementObject.DismissListener(closeListener);

and finally write onDismiss method

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

    }
0
votes

Tyler's example was the only example I could find that actually worked. The only thing that needs changed for the example to work is the call to the DismissListner method in the DialogFragment class. He has it as:

dialogFragementObject.DismissListner(closeListener);

This just needs to be a cast to whatever your class name of that DialogFragment is. For example:

((MyDialogFragment)dialogFragementObject).DismissListner(closeListener);