1

I have a DialogFragment class. I have to set the listener every time it shown (It has multiple cases in my app).

But when I rotate the screen mListener becomes null and there is a NullPointerExcpetion when I click a button. I can't implement the listener in the activity because it has a few cases for this dialog, each has different action.

The CustomDialog class:

MyDialogListener mListener;

public void show(FragmentManager fm, MyDialogListener listener) {
    mListener = listener;
    super.show(fm, "MyDialog");
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new AlertDialog.Builder(getActivity())
            .setTitle("Title")
            .setPositiveButton(android.R.string.ok, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int whichButton) {
                    mListener.onDialogPositiveClick();
                    // NullPointerException after a screen rotate
                }
            })
            .setNegativeButton(android.R.string.cancel, null)
            .create();
}

The activity class:

public void showMyFirstDialog() {
    new CutsomDialog().show(getFragmentManager(), mFirstListener);
}

public void showMySecondDialog() {
    new CutsomDialog().show(getFragmentManager(), mSecondListener);
}
6
  • post the logcat stacktrace Commented Dec 31, 2014 at 20:07
  • wait a minute please Commented Dec 31, 2014 at 20:08
  • faster, the new year's eve is in less than 1h :) Commented Dec 31, 2014 at 20:10
  • Why do you need the logcat? Commented Dec 31, 2014 at 20:11
  • mTitle, mMessage, and mListener are null Commented Dec 31, 2014 at 20:12

2 Answers 2

4

You cannot preserve instance fields of a Fragment (including a DialogFragment). The mechanism for having local data survive configuration changes is to set the fragment's arguments to a Bundle that contains your data; this bundle will survive configuration changes.

First, eliminate the show() method; it's not the correct approach. Instead, you can do something like this:

DialogFragment frag = new MyDialogFragment();
Bundle args = new Bundle();
args.putString("TITLE", "Dialog Title Goes Here");
args.putString("MESSAGE", "This is a dialog messaage");
frag.setArguments(args);

frag.show();

Then you can retrieve the title and message when you create the AlertDialog:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Bundle args = getArguments();
    String title = args.getString("TITLE");
    String message = args.getString("MESSAGE");

    // set up and return the alert dialog as before
}

Dealing with the DialogListener is a little more complex. You don't want to be holding a reference to that across config changes because it will lead back to the destroyed activity. Instead, you can arrange to retrieve the listener from the activity inside the fragment's onAttach() method:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    // now cast activity to your activity class and get a reference
    // to the listener
}

You may need to change your activity class(es) a bit to get this to work right. If you're using this dialog fragment from many activities, it's particularly helpful here to define an interface that the activities can implement to request a listener. It would then look something like this:

public interface DialogListenerProvider {
    DialogListener getDialogListener();
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (activity instanceof DialogListenerProvider) {
        mListener = ((DialogListenerProvider) activity).getDialogListener();
    } else {
        // throw an error
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

I have at the same activity two cases for this dialog, so I cant just implement it in the activity.
@User - That makes it easy; just cast the activity argument to a DialogListener in onAttach(), stash the reference in the instance field, and use it as needed.
1

The listener should not be passed in as an argument but instead implemented as part of interface both within the dialogfragment itself and may be an activity. That way, when the positive / negative click happens, you can update data on something and pass it to listener. The listener, when implemented by activity, would pass on the data to teh activity and you can take corresponding action in activity then.

Check these few examples - http://www.i-programmer.info/programming/android/7426-android-adventures-custom-dialogs-using-dialogfragment.html?start=2

http://android-developers.blogspot.com/2012/05/using-dialogfragments.html

Hope it helps.

5 Comments

I have at the same activity two cases for this dialog, so I cant just implement it in the activity.
Can you pls post more code, so that your calling mechanism can be understood better. Its slightly unclear what you are trying to achieve as of now.
mListener is null after a screen rotate, so if I click a button in the dialog it will throw a NullPointerException. Please tell my what part of code will help you.
pls post your activity code and dialogfragment code. I believe, your mListener is being initialized but due to rotation getting reset to null and the fragment is not reattached to the existign activity. The fragment can be retained across activity rotation using setRetainInstance true, so that even when activity is restarted, the fragment is just detached and reattached
This is not the problem. mFirstListener and mSecondListener are local variables of my activity. They are initialized at the declarion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.