【问题标题】:Why use newInstance for DialogFragment instead of the constructor?为什么对 DialogFragment 使用 newInstance 而不是构造函数?
【发布时间】:2016-01-09 05:36:01
【问题描述】:

查看DialogFragment 的documentation,可以看到用于初始化新警报对话框片段的静态newInstance 方法。我的问题是,为什么不使用构造函数来这样做,像这样:

public MyAlertDialogFragment(int title) {
    Bundle args = new Bundle();
    args.putInt("title", title);
    setArguments(args);
}

这不是完全一样还是有什么不同?最好的方法是什么?为什么?

【问题讨论】:

    标签: android constructor android-dialogfragment


    【解决方案1】:

    如果你创建一个通过构造函数接收对象的DialogFragment,当android 重新创建你的fragment时你会遇到问题。 这就是将会发生的事情:

    1. 您的代码会创建对话框,调用您创建的构造函数并将一些参数作为依赖项传递。
    2. 您的对话框运行,并使用您通过构造函数传递的依赖项
    3. 用户关闭应用
    4. 时间过去了,android 杀死了 Fragment 以释放内存
    5. 用户再次打开应用
    6. android 将使用默认构造函数重新创建您的对话框。不会传递任何参数!
    7. 您的对话框将处于不希望的状态。它可能会尝试使用您希望通过构造函数传递的实例变量,但由于它们不存在,您将获得空指针异常。

    为避免这种情况,您不需要依赖构造函数来建立依赖关系,而是在 Bundles 中(参数和保存的实例)。这可能会迫使您在某些类中实现 Parcelable,这很糟糕。

    编辑:您可以通过在开发设置中启用“不维护活动”来重现 Android 杀死应用程序(第 4 步)。这样就可以轻松测试了。

    【讨论】:

      【解决方案2】:

      Android 依赖于具有公共、零参数构造函数的 Fragment,以便它可以在不同时间重新创建它(例如配置更改、在之前被 Android 杀死后恢复应用状态等)。

      如果你没有这样的构造函数(例如问题中的那个),当它试图实例化一个构造函数时,你会看到这个错误:

      Fragment$InstantiationException: Unable to instantiate fragment 
      make sure class name exists, is public, and has an empty constructor that is public
      

      Fragment.setArguments(Bundle) 提供给它的参数将为您保存并提供给任何(重新)创建的新实例。使用静态方法创建 Fragment 提供了一种简单的方法来设置所需的参数,同时保持零参数构造函数。

      【讨论】:

      • 如果我添加 2 个构造函数会怎样?两种都是公开的,一种是零参数,另一种是我想要的参数……这不是也行吗?
      • 是的,我想这也行,你可以在自己构建时使用多参数构造函数,然后Android在重新创建它时会使用零参数构造函数。如果您在多参数构造函数中使用了 setArguments(..),参数将被正确保存。您真的只需要清楚地记住重新创建片段时会发生什么 - 静态工厂方法样式对我来说更加独特,但这可能是因为我(和许多其他人)习惯这样做。遵循标准约定将使您的代码更容易被他人理解。
      【解决方案3】:

      如果你用MyAlertDialogFragment(int title)重载了构造函数,如果Fragment需要重新创建并且不传递参数,Android系统仍然可能调用默认的MyAlertDialogFragment()构造函数。

      【讨论】:

      • 我很困惑,不确定这究竟是如何回答我的问题的……想澄清一下吗?
      • 您问:“我的问题是,为什么不使用构造函数来执行此操作,例如:public MyAlertDialogFragment(int title)”。我的回答是,如果你使用这个构造函数,如果 Android 系统重新创建了 Fragment,并且你想要传递的参数没有传递,它可能不会被调用。所以不要使用这种方法。
      • 这个答案没有意义。为此有一个构造函数是完全有效的;你只需要提供另一个没有参数的构造函数。
      • 我认为如果您旋转设备,这会给您带来问题。它不会调用您的构造函数,而是调用默认构造函数。因此,您打算通过重载的构造函数设置的任何内容都不会被执行。
      • 如果你不在构造函数中调用 setArguments(Bundle) ,这个答案是有意义的,这里不是这样。
      【解决方案4】:

      因为android在重新创建一个fragment时,它总是使用空构造函数,并且通过使用newInstance()你可以设置fragment在重新创建时使用的数据,例如当屏幕旋转时

      例如:

         public static FragmentExample newInstance(Parcelable uri) {
          FragmentExample fragmentExample = new FragmentExample();
      
          Bundle bundle = new Bundle();
          bundle.putParcelable("Uri", uri);
          fragmentExample.setArguments(bundle);
      
          return fragmentExample;
      }
      

      【讨论】:

      • 没有理由使用静态方法;只有两个构造函数。
      • 格伦,你甚至读过答案吗?两个构造函数都解决不了问题
      • 贾斯汀,你读过这个问题吗?在这种情况下(在构造函数中调用了setArguments),两个构造函数肯定可以解决问题。
      猜你喜欢
      • 2013-08-02
      • 1970-01-01
      • 1970-01-01
      • 2022-12-18
      • 1970-01-01
      • 2015-06-10
      • 2012-06-28
      • 1970-01-01
      相关资源
      最近更新 更多