Gra*_*ith 677 android android-fragments
我已经看到了两个在应用程序中实例化新Fragment的一般实践:
Fragment newFragment = new MyFragment();
Run Code Online (Sandbox Code Playgroud)
和
Fragment newFragment = MyFragment.newInstance();
Run Code Online (Sandbox Code Playgroud)
第二个选项使用静态方法newInstance(),通常包含以下方法.
public static Fragment newInstance()
{
MyFragment myFragment = new MyFragment();
return myFragment;
}
Run Code Online (Sandbox Code Playgroud)
起初,我认为主要的好处是我可以重载newInstance()方法以在创建Fragment的新实例时提供灵活性 - 但我也可以通过为Fragment创建重载构造函数来实现这一点.
我错过了什么?
一种方法比另一种方法有什么好处?还是只是好习惯?
yyd*_*ydl 1090
如果Android决定稍后重新创建Fragment,它将调用片段的无参数构造函数.所以重载构造函数不是一个解决方案.
话虽如此,将内容传递给Fragment以便在Android重新创建Fragment之后可用的setArguments方法是将包传递给方法.
因此,例如,如果我们想要将一个整数传递给片段,我们将使用类似的东西:
public static MyFragment newInstance(int someInt) {
MyFragment myFragment = new MyFragment();
Bundle args = new Bundle();
args.putInt("someInt", someInt);
myFragment.setArguments(args);
return myFragment;
}
Run Code Online (Sandbox Code Playgroud)
稍后在Fragment中,onCreate()您可以使用以下命令访问该整数:
getArguments().getInt("someInt", 0);
Run Code Online (Sandbox Code Playgroud)
即使Fragment以某种方式由Android重新创建,也可以使用此Bundle.
另请注意:setArguments只能在将Fragment附加到Activity之前调用.
Android开发人员参考中也记录了这种方法:https://developer.android.com/reference/android/app/Fragment.html
500*_*865 95
使用newInstance()我所看到的唯一好处如下:
您将拥有一个单独的位置,其中可以捆绑片段使用的所有参数,并且每次实例化片段时都不必编写下面的代码.
Bundle args = new Bundle();
args.putInt("someInt", someInt);
args.putString("someString", someString);
// Put any other arguments
myFragment.setArguments(args);
Run Code Online (Sandbox Code Playgroud)它是一种很好的方式告诉其他类它什么样的参数预计忠实地工作(虽然你应该能够处理的情况下,如果没有参数的片段中的实例绑定).
所以,我的看法是使用静态newInstance()来实例化片段是一种很好的做法.
小智 61
还有另一种方式:
Fragment.instantiate(context, MyFragment.class.getName(), myBundle)
Run Code Online (Sandbox Code Playgroud)
ps9*_*s95 44
虽然@yydl给出了一个令人信服的理由,说明为什么该newInstance方法更好:
如果Android决定稍后重新创建Fragment,它将调用片段的无参数构造函数.所以重载构造函数不是一个解决方案.
它仍然可以使用构造函数.要了解其原因,首先我们需要了解Android为何使用上述解决方法.
在使用片段之前,需要一个实例.Android调用YourFragment()(无参数构造函数)来构造片段的实例.在这里,您编写的任何重载构造函数都将被忽略,因为Android无法知道要使用哪一个.
在Activity的生命周期中,片段如上所述创建并被Android多次销毁.这意味着如果将数据放入片段对象本身,则一旦片段被销毁,它将丢失.
为解决方法,android要求您使用Bundle(调用setArguments())存储数据,然后可以从中访问YourFragment.参数bundle受Android保护,因此保证是持久的.
设置此捆绑包的一种方法是使用静态newInstance方法:
public static YourFragment newInstance (int data) {
YourFragment yf = new YourFragment()
/* See this code gets executed immediately on your object construction */
Bundle args = new Bundle();
args.putInt("data", data);
yf.setArguments(args);
return yf;
}
Run Code Online (Sandbox Code Playgroud)
但是,构造函数:
public YourFragment(int data) {
Bundle args = new Bundle();
args.putInt("data", data);
setArguments(args);
}
Run Code Online (Sandbox Code Playgroud)
可以做与newInstance方法完全相同的事情.
当然,这会失败,这也是Android希望您使用该newInstance方法的原因之一:
public YourFragment(int data) {
this.data = data; // Don't do this
}
Run Code Online (Sandbox Code Playgroud)
作为进一步的解释,这里是Android的片段类:
/**
* Supply the construction arguments for this fragment. This can only
* be called before the fragment has been attached to its activity; that
* is, you should call it immediately after constructing the fragment. The
* arguments supplied here will be retained across fragment destroy and
* creation.
*/
public void setArguments(Bundle args) {
if (mIndex >= 0) {
throw new IllegalStateException("Fragment already active");
}
mArguments = args;
}
Run Code Online (Sandbox Code Playgroud)
请注意,Android要求仅在构造时设置参数,并保证这些参数将被保留.
编辑:正如@JHH的评论所指出的,如果你提供一个需要一些参数的自定义构造函数,那么Java将不会为你的片段提供一个没有arg的默认构造函数.因此,这需要您定义一个无参数构造函数,这是您可以使用newInstance工厂方法避免的代码.
编辑:Android不允许再使用重载的构造函数.您必须使用该newInstance方法.
Ily*_*man 17
我不同意 yydi的回答说:
如果Android决定稍后重新创建Fragment,它将调用片段的无参数构造函数.所以重载构造函数不是一个解决方案.
我认为这是一个解决方案而且是一个好的解决方案,这正是它由Java核心语言开发的原因.
这是真的,Android系统可以破坏和重建你的Fragment.所以你可以这样做:
public MyFragment() {
// An empty constructor for Android System to use, otherwise exception may occur.
}
public MyFragment(int someInt) {
Bundle args = new Bundle();
args.putInt("someInt", someInt);
setArguments(args);
}
Run Code Online (Sandbox Code Playgroud)
即使系统重新创建,它也允许您someInt从getArguments()后者Fragment开始.这是比static构造函数更优雅的解决方案.
对于我的意见,static构造函数是无用的,不应该使用.如果将来你想扩展它Fragment并为构造函数添加更多功能,它们也会限制你.使用static构造函数,您无法执行此操作.
更新:
Android添加了检查,标记所有非默认构造函数并显示错误.
出于上述原因,我建议禁用它.
Raf*_*ols 14
一些kotlin代码:
companion object {
fun newInstance(first: String, second: String) : SampleFragment {
return SampleFragment().apply {
arguments = Bundle().apply {
putString("firstString", first)
putString("secondString", second)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你可以得到这个论点:
val first: String by lazy { arguments?.getString("firstString") ?: "default"}
val second: String by lazy { arguments?.getString("secondString") ?: "default"}
Run Code Online (Sandbox Code Playgroud)
小智 5
我最近来了。但我刚刚知道的一些事情可能会对你有所帮助。
如果您使用 Java,则无需进行太多更改。但对于 Kotlin 开发者来说,我认为以下一些片段可以让你成为一个可以运行的地下室:
inline fun <reified T : SampleFragment> newInstance(text: String): T {
return T::class.java.newInstance().apply {
arguments = Bundle().also { it.putString("key_text_arg", text) }
}
}
Run Code Online (Sandbox Code Playgroud)
val f: SampleFragment = SampleFragment.newInstance("ABC")
// or val f = SampleFragment.newInstance<SampleFragment>("ABC")
Run Code Online (Sandbox Code Playgroud)
fun newInstance(): ChildSampleFragment {
val child = UserProfileFragment.newInstance<ChildSampleFragment>("XYZ")
// Do anything with the current initialized args bundle here
// with child.arguments = ....
return child
}
Run Code Online (Sandbox Code Playgroud)
快乐编码。