Fragment 实例化浅析
智能微投项目中,蓝牙遥控器与 Device 连接成功后,按返回键,设置出现闪退,定位打印如下:
查看并分析打印信息,闪退的打印信息以前也出现过,但没有重视,在微投项目中百分百复现,关键打印信息如下:
Caused by: android.support.v4.app.Fragment$InstantiationException:
Unable to instantiate fragment ,
make sure class name exists, is public,
and has an empty constructor that is public
定位问题出现在make sure class name exists, is public, and has an empty constructor that is public
异常的原因是没有 Fragment 无参数 public 构造函数,添加 Public 无参构造函数后,微投项目问题解决,但为什么其他项目能正常运行,而微投在蓝牙配对后会出现闪退。
查看Fragment 源码Instantiation方法:
This is the same as calling its empty 构造函数,instantiate 函数catch 打印正好是闪退异常时候打印,异常的确来源于此
instantiate 函数功能是通过 Java 反射机制实例化 Fragment;
Fragment f = (Fragment)clazz.newInstance();
查看newInstance()源码:
The class is instantiated expression with an empty argument list
类被实例化需无参 构造函数;
查看Fragment 无参构造函数源码:
总结:当系统因为内存紧张杀死非前台进程(并非真正的杀死),然后我们将被系统杀掉的非前台app带回前台,如果这个时候有UI是呈现在Fragment中,那么会因为restore造成fragment需要通过反射实例对象,从而将之前save的状态还原,而这个反射实例对象就是fragment需要Public的empty constructor的关键所在
问题解决方案:
- 添加 public 无参构造函数;
- 在含有参数的 Fragment 构造函数上添加注解
@SuppressLint("ValidFragment")
(避免使用非默认构造函数,因为Fragment源码中用到反射构造了对象,是无参数的构造函数)