Android 为什么要在片段中避免非默认构造函数?

Android 为什么要在片段中避免非默认构造函数?,android,android-fragments,Android,Android Fragments,我正在创建一个带有片段的应用程序,在其中一个片段中,我创建了一个非默认构造函数,并收到以下警告: Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead 有人能告诉我为什么这不是个好主意吗 您能否建议我如何做到这一点: public static class MenuFragment extends ListFragment

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

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

不使用非默认构造函数

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

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);
之后,在片段访问数据中:

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

仅此而已。

您的
片段
不应该有构造函数,因为
片段管理器
是如何实例化它的。 您应该使用所需的参数定义一个
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 ;
}
并在创建时阅读这些参数:

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

    //...
}

这样,如果分离并重新附加,对象状态可以通过参数存储,就像附加到
Intent
s的
bundle
一样。

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

您应该通过bundle传递参数的原因是,当系统恢复
片段
(例如在配置更改时),它将自动恢复您的
bundle

onCreate
onCreateView
这样的回调应该从
bundle
读取参数-这样可以保证将
片段的状态正确恢复到初始化
片段时的状态(注意此状态可能不同于传递给
onCreate/onCreateView
onSaveInstanceState捆绑包


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

如果您对某些类使用参数,请尝试此方法

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

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


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

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

可能的du也许还有其他的不,这些都没有帮助。他们没有回答我的问题。但还是要谢谢你:)@BlaineOmega事实上,这一个特别:肯定回答了你的问题。在方向更改或其他导致重新创建片段的事件中,Android使用默认构造函数以及作为参数传递的包。如果您使用的是自定义构造函数,那么一旦由于这些事件之一而重新创建了片段,您在自定义构造函数中所做的一切都将丢失。谢谢,但这回答了为什么,而不是如何。这在我原始注释中的第一个和第二个链接中有介绍。如何传递对象?我想传递一个上下文对象或任何其他对象。捆绑包可以携带序列化的Java对象以及对象。另外,您不应该传递
上下文,因为可以通过片段的访问该信息。在执行此操作的片段中
Type value=getArguments().getType(“key”)
?@Muhammad Babar:如果我是你,我会将它添加到
newInstance()
方法中。例如:
publicstaticfragmentname newInstance(您的变量){}
。正如Android文档所建议的那样,不要创建带有参数的构造函数,因为默认构造函数(不带参数)将在片段重新启动后自动调用。@MuhammadBabar onCreateView解释得很好。谢谢如果我是那个被问到这个问题的人,我会给你一个提示,你不能再使用非默认构造函数(无论出于什么原因)。。。。它给出了一个编译器错误(过去是一个警告)。这实际上是一个不好的建议。一旦碎片管理器重新创建碎片,您将丢失mSomeInstance。同意,SomeClass应可打包,并使用setArguments()存储在捆绑包中