DialogFragment - retaining listener after screen r

2019-01-21 08:09发布

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

3条回答
Fickle 薄情
2楼-- · 2019-01-21 08:30

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

查看更多
干净又极端
3楼-- · 2019-01-21 08:33

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().

查看更多
SAY GOODBYE
4楼-- · 2019-01-21 08:48

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);
    }
}
查看更多
登录 后发表回答