Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DialogFragment - retaining listener after screen rotation

I have a DialogFragment which creates a DatePickerDialog. I'm using a static method called newInstance to set the initial values in order to use the default empty constructor. However, how am I supposed to set the listener? After the screen rotation, when clicking in the "Done" button, the listener doesn't do anything since it does not exist.

public class DatePickerFragment extends DialogFragment {
    public static final String ARG_YEAR = "year";
    public static final String ARG_MONTH = "month";
    public static final String ARG_DAY = "day";

    private OnDateSetListener listener_;

    public static DatePickerFragment newInstance(OnDateSetListener listener, int year, int month, int day) {
        final DatePickerFragment date_picker = new DatePickerFragment();
        date_picker.setListener(listener);

        final Bundle arguments = new Bundle();
        arguments.putInt(ARG_YEAR, year);
        arguments.putInt(ARG_MONTH, month);
        arguments.putInt(ARG_DAY, day);
        date_picker.setArguments(arguments);

        return date_picker;
    }

    private void setListener(OnDateSetListener listener) {
        listener_ = listener;
    }

    @Override
    public Dialog onCreateDialog(Bundle saved_instance_state) {
        final Bundle arguments = getArguments();
        final int year = arguments.getInt(ARG_YEAR);
        final int month = arguments.getInt(ARG_MONTH);
        final int day = arguments.getInt(ARG_DAY);

        return new DatePickerDialog(getActivity(), listener_, year, month, day);
    }
}
like image 310
Renato Rodrigues Avatar asked Dec 26 '12 15:12

Renato Rodrigues


3 Answers

However, how am I supposed to set the listener?

You update the listener reference in the onCreate method of the Activity:

private OnDateSetListener mOds = new OnDateSetListener() {

    @Override
    public void onDateSet(DatePicker view, int year, int monthOfYear,
            int dayOfMonth) {
             // do important stuff
    }
};

and in the onCreate method:

if (savedInstanceState != null) {
    DatePickerFragment dpf = (DatePickerFragment) getSupportFragmentManager()
            .findFragmentByTag("theTag?");
    if (dpf != null) {
        dpf.setListener(mOds);
    }
}
like image 102
user Avatar answered Oct 20 '22 09:10

user


In my opinion there is a more efficient way of doing this, using the Fragment lifecycle. You can use the Fragment lifecycle callbacks onAttach() and onDetach() to automatically cast the activity as a Listener like so:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        _listener = (OnDateSetListener)activity;
    } catch(ClassCastException e) {
        // check if _listener is null before using,
        // or throw new ClassCastException("hosting activity must implement OnDateSetListener");
    }
}

@Override
public void onDetach() {
    super.onDetach();
    _listener = null;
}

This technique is officially documented here

like image 39
d370urn3ur Avatar answered Oct 20 '22 11:10

d370urn3ur


The answer of Luksprog is correct, I just want to point out, the key of the solution is the findFragmentByTag() function. Because the activity will be also recreated after screen rotation, you cannot call the setter function of its member Fragment variable, instead you should find the old fragment instance with this function.

Btw, the tag is the second parameter when you call DialogFragment.show().

like image 2
cn123h Avatar answered Oct 20 '22 10:10

cn123h