为啥要避免片段中的非默认构造函数?
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
。
像onCreate
或onCreateView
这样的回调应该从bundle
中读取参数 - 这样您就可以保证将fragment
的状态正确地恢复到fragment
初始化时使用的相同状态(请注意,此状态可能与传递给 onCreate/onCreateView
的 onSaveInstanceState 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
附加到Intent
s。
【讨论】:
【参考方案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】:如果片段在配置更改后使用非默认构造函数,片段将丢失所有数据。
【讨论】:
以上是关于为啥要避免片段中的非默认构造函数?的主要内容,如果未能解决你的问题,请参考以下文章