为啥要避免片段中的非默认构造函数?

Posted

技术标签:

【中文标题】为啥要避免片段中的非默认构造函数?【英文标题】:Why do I want to avoid non-default constructors in fragments?为什么要避免片段中的非默认构造函数? 【发布时间】:2012-08-17 06:37:12 【问题描述】:

我正在使用Fragments 创建一个应用程序,在其中一个应用程序中,我创建了一个非默认构造函数并收到以下警告:

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

谁能告诉我为什么这不是一个好主意?

您能否也建议我如何做到这一点:

public static class MenuFragment extends ListFragment 
    public ListView listView1;
    Categories category;

    //this is my "non-default" constructor
    public MenuFragment(Categories category)
        this.category = category;
    ....

不使用非默认构造函数?

【问题讨论】:

Best practice for instantiating a new android Fragment 和 ***.com/questions/10450348/… 和 ***.com/questions/11602433/… 可能重复,可能还有其他人 不,那些没有帮助。他们没有回答我的问题。但是还是谢谢你:) @BlaineOmega 实际上特别是这个:***.com/a/11602478/321697 肯定会回答您的问题。在导致重新创建 Fragment 的方向更改或其他事件时,Android 使用默认构造函数以及作为参数传递的 Bundle。如果您使用的是自定义构造函数,那么一旦由于这些事件之一重新创建片段,您在自定义构造函数中所做的一切都会丢失。 谢谢,但这回答了为什么,而不是如何。 我的原始评论中的第一个和第二个链接涵盖了这一点。 【参考方案1】:

似乎没有一个答案真正回答“为什么使用 bundle 传递参数而不是非默认构造函数”

你应该通过bundle传递参数的原因是因为当系统恢复fragment时(例如配置更改),它会自动恢复你的bundle

onCreateonCreateView 这样的回调应该从bundle 中读取参数 - 这样您就可以保证将fragment 的状态正确地恢复到fragment 初始化时使用的相同状态(请注意,此状态可能与传递给 onCreate/onCreateViewonSaveInstanceState bundle 不同)

使用静态newInstance() 方法的建议只是一个建议。您可以使用非默认构造函数,但请确保在该构造函数主体内的bundle 中填充初始化参数。并在onCreate()onCreateView() 方法中读取这些参数。

【讨论】:

很好解释。谢谢。如果我是问这个问题的人,我会给你打勾 你不能再使用非默认构造函数(无论出于何种原因)......它会给出编译器错误(曾经是警告)。【参考方案2】:

创建一个捆绑对象并插入您的数据(在本例中为您的Category 对象)。请注意,您不能将此对象直接传递到包中,除非它是可序列化的。 我认为最好在片段中构建你的对象,并且只将一个 id 或其他东西放入包中。这是创建和附加捆绑包的代码:

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);

之后,在您的片段中访问数据:

Type value = getArguments().getType("key");

就是这样。

【讨论】:

如何传递一个对象?我想传递一个上下文对象或任何其他对象。 Bundles 可以携带序列化的 Java 对象以及 Parcelable 对象。此外,您不应传递Context,因为可以通过片段的getActivity() method 访问该信息。 在片段中在哪里执行此操作Type value = getArguments().getType("key");? @Muhammad Babar:如果我是你,我会把它添加到newInstance() 方法中。例如:public static FragmentName newInstance(your variables)。正如 Android 文档所建议的那样,不要使用带参数的构造函数,因为默认的构造函数(不带参数)会在片段重启后自动调用。 @MuhammadBabar onCreateView 没问题【参考方案3】:

您的Fragment 不应该有构造函数,因为FragmentManager 如何实例化它。 您应该使用您需要的参数定义一个 newInstance() 静态方法,然后将它们捆绑并将它们设置为片段的参数,稍后您可以使用 Bundle 参数访问它。

例如:

public static MyFragment newInstance(int title, String message) 
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle(2);
    bundle.putInt(EXTRA_TITLE, title);
    bundle.putString(EXTRA_MESSAGE, message);
    fragment.setArguments(bundle);
    return fragment ;

onCreate阅读这些论点:

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...

这样,如果分离并重新附加,对象状态可以通过参数存储,很像bundles附加到Intents。

【讨论】:

【参考方案4】:

如果你对某个类使用参数。试试这个

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance)
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;

【讨论】:

这实际上是一个糟糕的建议。一旦 FragmentManager 重新创建 Fragment,您将丢失 mSomeInstance。 同意,SomeClass 应该可以使用 setArguments() 打包并存储在包中【参考方案5】:

我认为,静态构造函数和两个构造函数(将参数存储到 Fragment 的参数包中的空的和参数化的构造函数)之间没有区别,很可能,创建这个经验法则是为了减少忘记实现 no-arg 的可能性Java 中的构造函数,在存在重载时不会隐式生成。

在我的项目中,我使用 Kotlin,并使用主要的无参数构造函数和次要的参数构造函数实现片段,将它们存储到一个包中并将其设置为片段参数,一切正常。

【讨论】:

【参考方案6】:

如果片段在配置更改后使用非默认构造函数,片段将丢失所有数据。

【讨论】:

以上是关于为啥要避免片段中的非默认构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

golang函数中的参数为啥不支持默认值

子类为啥要调用父类的构造函数

为啥标准不将模板构造函数视为复制构造函数?

为啥 C++ 构造函数在继承中需要默认参数?

内联使用成员对象的非默认显式构造函数

为啥并不总是有默认构造函数[重复]