Android修改配置后,比如切换系统语言。activity会被销毁然后重建.
当碰到这种销毁重建后,fragment如果没有无参构造方法,则会报错
报错信息如下
androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.XxxFragment: could not find Fragment constructor
在Fragment中找到这个报错的出处,代码如下
/**
* Create a new instance of a Fragment with the given class name. This is
* the same as calling its empty constructor, setting the {@link ClassLoader} on the
* supplied arguments, then calling {@link #setArguments(Bundle)}.
*
* @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.
* @deprecated Use {@link FragmentManager#getFragmentFactory()} and
* {@link FragmentFactory#instantiate(ClassLoader, String)}, manually calling
* {@link #setArguments(Bundle)} on the returned Fragment.
*/
@Deprecated
@NonNull
public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
@Nullable Bundle args) {
try {
Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
context.getClassLoader(), fname);
//通过无参构造方法反射获得fragment的实例
Fragment f = clazz.getConstructor().newInstance();
//用frangment的setArguments()传参
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.setArguments(args);
}
return f;
} catch (java.lang.InstantiationException 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 (IllegalAccessException 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 (NoSuchMethodException e) {
//在这里报的错误
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": could not find Fragment constructor", e);
} catch (InvocationTargetException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": calling Fragment constructor caused an exception", e);
}
}
从代码中可以看出,如果创建fragment时需要给fragment传递参数,最好用fragment.setArguments()方法传递参数,不要通过构造方法传递。防止在activity重建时因为没有无参构造方法,而报错。