(一)具体报错
androidx.fragment.app.Fragment$InstantiationException:
Unable to instantiate fragment com.yl.newtaobaounion.ui.fragment.HomeViewPagerFragment: could not find Fragment constructor
(二)报错原因
无法实例化 fragment 找不到 Fragment 构造函数 android - 堆栈溢出 (stackoverflow.com)
为什么使用Fragment时必须提供一个无参的构造函数? - 简书 (jianshu.com)
使用Fragment必须提供一个空参构造,因为当Fragment因为某种原因重新创建时,会调用到onCreate方法传入之前保存的状态, 在instantiate方法中通过反射无参构造函数创建一个Fragment,并且为Arguments初始化为原来保存的值, 而此时如果没有无参构造函数就会抛出异常,造成程序崩溃。
在fragment类的空参源码注释中也有提到
/**
* Constructor used by the default {@link FragmentFactory}. You must
* {@link FragmentManager#setFragmentFactory(FragmentFactory) set a custom FragmentFactory}
* if you want to use a non-default constructor to ensure that your constructor
* is called when the fragment is re-instantiated.(默认构造器)
*
* <p>It is strongly recommended to supply arguments with {@link #setArguments}
* and later retrieved by the Fragment with {@link #getArguments}. These arguments
* are automatically saved and restored alongside the Fragment.
(强烈建议使用setArguments()方法为fragment保存参数,使其在切换时可以找到原来的状态)
*
* <p>Applications should generally not implement a constructor. Prefer
* {@link #onAttach(Context)} instead. It is the first place application code can run where
* the fragment is ready to be used - the point where the fragment is actually associated with
* its context. Some applications may also want to implement {@link #onInflate} to retrieve
* attributes from a layout resource, although note this happens when the fragment is attached.
(创建fragment通常不建议自定义带有参数的构造,即建议使用空参构造,避免程序出现异常)
*/
public Fragment() {
initLifecycle();
}
而我在使用Fragment时,只为其提供了一个有参构造,而没有提供无参构造,导致程序切换fragment后切换回来的时候崩溃
但我之所以只为其提供了一个有参构造是因为我只允许fragment被创建时是带有参数的,但若只提供无参构造,如何获取参数呢?
(三)解决办法
不自定义带参构造方法,直接编写一个静态的getInstance(要传入的参数)方法来获取fragment的实例,在此方法中调用空参构造创建Fragment的对象,并调用setArguments()方法为fragment保存状态。
kotlin示例如下:
class HomeViewPagerFragment : BaseFragment(),
IRecommendDataCallback {
companion object {
lateinit var fragment: HomeViewPagerFragment
//参数传递
//使用fragment必须提供一个无参构造,
// 因为当Fragment因为某种原因重新创建时,会调用到onCreate方法传入之前保存的状态,
// 在instantiate方法中通过反射无参构造函数创建一个Fragment,并且为Arguments初始化为原来保存的值,
// 而此时如果没有无参构造函数就会抛出异常,造成程序崩溃。
fun getInstance(categoriesData: CategoriesData?): HomeViewPagerFragment {
val args = Bundle()
args.putSerializable("categoriesData", categoriesData)
fragment = HomeViewPagerFragment()
fragment.setArguments(args)
return fragment
}
}
//若后面的其他地方需要使用到我们传进来的参数,直接调用
//arguments?.getSerializable("categoriesData") as CategoriesData即可
}