Android从未直接调用非默认构造函数(也不是工厂方法) – 从技术上讲,使用它并不重要.您可以在添加Fragment之前随时调用setArguments(在任意方法中,即使在构造函数中),如果重新创建Fragment,则该bundle将被保存/还原.视图还具有由Android调用的特殊构造函数,但如果需要,您可以自由使用任意参数(它们不会被Android调用).
Fragment.setArguments代码:
/**
* 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;
}
片段代码:
/**
* Create a new instance of a Fragment with the given class name. This is
* the same as calling its empty constructor.
*
* @param context The calling context being used to instantiate the fragment.
* This is currently just used to get its ClassLoader.
* @param fname The class name of the fragment to instantiate.
* @param args Bundle of arguments to supply to the fragment,which it
* can retrieve with {@link #getArguments()}. May be null.
* @return Returns a new fragment instance.
* @throws InstantiationException If there is a failure in instantiating
* the given fragment class. This is a runtime exception; it is not
* normally expected to happen.
*/
public static Fragment instantiate(Context context,String fname,Bundle args) {
try {
Class> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache,see if it's real,and try to add it
clazz = context.getClassLoader().loadClass(fname);
sClassMap.put(fname,clazz);
}
Fragment f = (Fragment)clazz.newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.mArguments = args;
}
return f;
} catch (ClassNotFoundException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists,is public,and has an"
+ " empty constructor that is public",e);
} catch (java.lang.InstantiationException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists,e);
} catch (IllegalAccessException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists,e);
}
}
当Android要创建片段的实例时,将调用Fragment.instantiate.它通过Class.newInstance简单的调用,它是使用默认的零arg构造函数创建一个类的Java方法.看这个代码,似乎没有问题,创建额外的构造函数和在其中调用setArguments.
作为惯例,使用片段时通常使用工厂方法.大多数official sample Fragment code也采用工厂方法.以下是一些可能的原因:
>如果您正在编写一个自定义构造函数(带有参数),那么您也必须指定一个零对象构造函数.一个常见的错误是创建一个自定义构造函数,但是忘记定义一个零对象构造函数 – 当Android尝试在重新创建片段时尝试调用零对象构造函数,这将导致崩溃.>创建自定义构造函数时,您可能会尝试直接将构造函数参数分配给字段.这是任何其他Java类写的几乎相当(因此你将如何自然地想写类).由于Android只会调用片段上的零对象构造函数,所以这些数据将无法用于任何重新创建的实例.如你所知,使用setArguments是解决这个问题的方法.即使您可以在构造函数中执行此操作,使用工厂方法使得更加明显的是,此类不能以正常方式构造,从而减少了上述错误(或类似情况)的可能性.