【问题标题】:DialogFragment - retaining listener after screen rotationDialogFragment - 屏幕旋转后保留监听器
【发布时间】:2017-02-19 05:18:18
【问题描述】:

我有一个创建 DatePickerDialog 的 DialogFragment。我正在使用一个名为newInstance 的静态方法来设置初始值,以便使用默认的空构造函数。但是,我应该如何设置监听器?屏幕旋转后,当点击“完成”按钮时,监听器不做任何事情,因为它不存在。

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

【问题讨论】:

    标签: android android-fragments android-lifecycle


    【解决方案1】:

    但是,我应该如何设置监听器?

    您在ActivityonCreate 方法中更新监听器引用:

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

    onCreate 方法中:

    if (savedInstanceState != null) {
        DatePickerFragment dpf = (DatePickerFragment) getSupportFragmentManager()
                .findFragmentByTag("theTag?");
        if (dpf != null) {
            dpf.setListener(mOds);
        }
    }
    

    【讨论】:

    • +1,同样为了澄清,重要的是使用对话框片段的标签重新应用监听器。此标记在对话框片段show 方法的第二个参数中指定。
    • DialogFragment 不是支持库片段,因此应使用 DatePickerFragment dpf = (DatePickerFragment) getSupportFragmentManager() .findFragmentByTag("theTag?"); DatePickerFragment dpf = (DatePickerFragment) getFragmentManager() .findFragmentByTag("theTag?"); 代替
    • @VelmuruganV DialogFragment 在支持库中可用developer.android.com/reference/android/support/v4/app/…
    • 抱歉,我不知道。感谢您纠正我@Luksprog
    • 我们不得不处理这些事情真是太糟糕了。我们都应该去向谷歌报告一个问题,去制作一个不错的 API,而不是强迫我们解决所有问题。
    【解决方案2】:

    在我看来,使用 Fragment 生命周期有一种更有效的方法。您可以使用 Fragment 生命周期回调 onAttach()onDetach() 自动将活动转换为侦听器,如下所示:

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

    此技术已正式记录在 here

    【讨论】:

    • 是的,但是通过这种方式,您不能在具有不同侦听器的 Activity 中多次使用同一个类(我说是 DialogFragment)...
    • 为什么不呢?只需在 Activity 上实现您想要的任何侦听器接口,并将其转换为 DialogFragment 中的不同侦听器实例。如果你想让一些可选的,你可以有更复杂的 ClassCast 错误处理。
    • 我的意思是,如果同一个 Activity 需要使用同一个 DialogFragment 两次并且(如你所建议的),Activity 继承自监听器,当调用 Activity 中的监听器方法时你不知道哪个是这样的......我认为最好使用两个不同的监听器实例(它们不能是活动)。我所说的依赖于假设,对于良好的设计,我们避免循环依赖,并且 DialogFragment 定义了它自己的侦听器类型并且它不知道 Activity 特化。
    • 我不明白您的意思:“当调用侦听器方法时,您不知道是哪种情况”。你的意思是,哪个 DialogFragment 实例调用了监听器方法?为什么不能在侦听器方法中传递有关 DialogFragment 的识别信息?我必须查看一些代码才能理解您的用例。事实是,DialogFragment 已经与 Activity 密切相关,这是处理 DialogFragment 最常见用法的最简单方法。它也被正式记录在案,因此在生产应用程序中遇到它并不奇怪。
    • @d370urn3ur,可能 ARLabs 的意思是 Activity 可以扩展许多扩展同一个 DialogFragment 的片段。在这种情况下,听众可能会有所不同。
    【解决方案3】:

    Luksprog 的答案是正确的,我只想指出,解决的关键是 findFragmentByTag() 函数。因为activity也会在屏幕旋转后重新创建,所以不能调用它的成员Fragment变量的setter函数,而是通过这个函数找到旧的fragment实例。

    顺便说一句,标签是调用DialogFragment.show()时的第二个参数。

    【讨论】:

    • 我发现如果你从Fragment调用DialogFragment,在屏幕旋转后在onCreateView()调用fragmentManager.findFragmentByTag(),它可能会返回null。在这种情况下,请尝试致电childFragmentManager.findFragmentByTag()。或查看 @d370urn3ur 的答案。在这种情况下,您应该在 Activity 中设置回调。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    相关资源
    最近更新 更多