我已经看到了在应用程序中实例化一个新Fragment的两个通用实践:
Fragment newFragment = new MyFragment();
and
Fragment newFragment = MyFragment.newInstance();
第二个选项使用静态方法newInstance(),通常包含以下方法。
public static Fragment newInstance()
{
MyFragment myFragment = new MyFragment();
return myFragment;
}
起初,我认为主要的好处是,我可以重载newInstance()方法,以便在创建新的Fragment实例时提供灵活性——但我也可以通过为Fragment创建重载构造函数来实现这一点。
我错过什么了吗?
一种方法相对于另一种方法有什么好处?还是说这只是一个很好的练习?
我不同意yydi的回答:
如果Android决定稍后重新创建Fragment,它会调用
片段的无参数构造函数。重载
构造函数不是解决方案。
我认为这是一个很好的解决方案,这正是它被Java核心语言开发的原因。
确实,Android系统可以破坏和重建你的碎片。所以你可以这样做:
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);
}
它将允许您稍后从getArguments()中提取someInt,即使该Fragment已被系统重新创建。这是比静态构造函数更优雅的解决方案。
在我看来,静态构造函数是无用的,不应该使用。此外,如果将来你想扩展这个Fragment并向构造函数添加更多功能,它们也会限制你。使用静态构造函数你不能这样做。
更新:
Android增加了标记所有非默认构造函数错误的检查。
由于上面提到的原因,我建议禁用它。
如果Android决定稍后重新创建Fragment,它会调用Fragment的无参数构造函数。因此重载构造函数不是解决方案。
话虽如此,传递东西到你的碎片,使他们可用后,一个碎片被Android重新创建是传递一个捆绑到setArguments方法。
因此,例如,如果我们想要传递一个整数到片段,我们将使用如下方式:
public static MyFragment newInstance(int someInt) {
MyFragment myFragment = new MyFragment();
Bundle args = new Bundle();
args.putInt("someInt", someInt);
myFragment.setArguments(args);
return myFragment;
}
稍后在Fragment onCreate()中,你可以使用:
getArguments().getInt("someInt", 0);
即使Fragment被Android以某种方式重新创建,这个Bundle也将可用。
还要注意:setArguments只能在Fragment被附加到Activity之前被调用。
这种方法也记录在android开发者参考:https://developer.android.com/reference/android/app/Fragment.html
由于关于最佳实践的问题,我想补充一点,在使用一些REST web服务时,使用混合方法来创建片段通常是一个好主意
我们不能传递复杂的对象,例如一些用户模型,以防显示用户片段
但我们能做的是,签入onCreate那个用户!=null,如果不是-那么把他从数据层,否则-使用现有。
通过这种方式,我们获得了在Android和snappiness的情况下通过userId重新创建片段的能力,以及通过持有对象本身或仅它的id来创建片段的能力
是这样的:
public class UserFragment extends Fragment {
public final static String USER_ID="user_id";
private User user;
private long userId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
userId = getArguments().getLong(USER_ID);
if(user==null){
//
// Recreating here user from user id(i.e requesting from your data model,
// which could be services, direct request to rest, or data layer sitting
// on application model
//
user = bringUser();
}
}
public static UserFragment newInstance(User user, long user_id){
UserFragment userFragment = new UserFragment();
Bundle args = new Bundle();
args.putLong(USER_ID,user_id);
if(user!=null){
userFragment.user=user;
}
userFragment.setArguments(args);
return userFragment;
}
public static UserFragment newInstance(long user_id){
return newInstance(null,user_id);
}
public static UserFragment newInstance(User user){
return newInstance(user,user.id);
}
}
在android中使用参数实例片段的最佳实践是在你的片段中有静态工厂方法。
public static MyFragment newInstance(String name, int age) {
Bundle bundle = new Bundle();
bundle.putString("name", name);
bundle.putInt("age", age);
MyFragment fragment = new MyFragment();
fragment.setArguments(bundle);
return fragment;
}
您应该避免使用片段的实例来设置字段。因为每当android系统重新创建fragment时,如果它觉得系统需要更多内存,它就会使用不带参数的构造函数重新创建fragment。
你可以在这里找到更多关于用参数实例化片段的最佳实践的信息。