首先,我已经知道FragmentManager经常破坏,然后使用默认构造函数重新创建片段.编码器必须在工厂方法中将重要的事物保存在一束参数中,然后在每次在onCreate(Bundle)中重新生成片段时将它们取出.
public class MyFragment extends Fragment { private static final String MY_STRING_CONSTANT = "param"; private int mIntegerMember; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mIntegerMember= getArguments().getInt(MY_STRING_CONSTANT); } }
我的问题是,这是有区别的:
// Inside MyFragment.java public MyFragment() { // No-argument constructor required by the FragmentManager. } public static MyFragment newInstance(int param) { // Factory method MyFragment fragment = new MyFragment(); Bundle args = new Bundle(); args.putInt(MY_STRING_CONSTANT,param); fragment.setArguments(args); return fragment; } // Somewhere else FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.add(R.id.frame_layout,MyFragment.newInstance(123)).commit();
和这个:
// Inside MyFragment.java public MyFragment() { // No-argument constructor required by the FragmentManager. } public MyFragment(int param) { // Parameterized constructor Bundle args = new Bundle(); args.putInt(MY_STRING_CONSTANT,param); setArguments(args); } // Somewhere else FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.add(R.id.frame_layout,new MyFragment(123)).commit();
我看不到什么可以阻止FragmentManager调用无参数的构造函数.并且在保存参数化构造函数(Bundle对象)中的数据将在onCreate()期间保留并恢复,就像使用工厂方法一样.
解决方法
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是解决这个问题的方法.即使您可以在构造函数中执行此操作,使用工厂方法使得更加明显的是,此类不能以正常方式构造,从而减少了上述错误(或类似情况)的可能性.