Android开发时,如何在初始化一个Fragment的同时,向Fragment中传入参数?
一、方法
话不多说,直接上方法
1、在实例化Fragment时,调用fragment对象的setArguments方法,将要传递进去的数据封装为Bundle后传给fragment对象
2、在fragment要用该数据的地方调用getArguments获取Bundle对象,再通过解析Bundle对象获取传入的数据
3、实际使用中,更加推荐将步骤1里的操作封装为Fragment类的静态方法,更加简洁、规范
要实例化该fragment时,直接调用该方法并传入参数即可
二、源码分析
如果只是为了解决题目描述中的问题,其实只看上面的代码即可。后面的部分是为了(水一下文章字数)分析一下为什么推荐该方法。
在Java语言中,初始化一个类的同时传递参数,最常用的方式是通过类的构造函数来传入参数。但是初始化Fragment时却不能这样做,这是因为Android在部分场景下会重建当前Activity以及其中的Fragment(最典型的例子就是手机横竖屏切换),重建Fragment时会默认调用Fragment的无参构造函数而不是我们定义的含参构造函数,导致重建后的Fragment丢失了数据。
而使用上述setArguments方法传参时,会为Fragment中保存Bundle数据的mArguments变量赋值,简化后的源码示意如下:
mArguments默认是null
public class Fragment implements ComponentCallbacks,
View.OnCreateContextMenuListener, LifecycleOwner, ViewModelStoreOwner {
...
Bundle mArguments;
...
}
调用该方法才会为mArguments赋值
public void setArguments(Bundle args) {
if (mIndex >= 0) {
throw new IllegalStateException("Fragment already active");
}
mArguments = args;
}
在重建Fragment时,会判断当前fragment是否储存了参数(即mArguments是否为不为空),如果包含了参数,则会将原来保存的参数传递给新建的Fragment,从而避免了重建的Fragment丢失数据
if (mArguments != null) {
mArguments.setClassLoader(context.getClassLoader());
}
mInstance = Fragment.instantiate(context, mClassName, mArguments);
从instantiate方法源码中,也能发现,重建Fragment调用的是无参构造函数,并且当args不为null时,重新调用setArguments方法为新Fragment传递数据
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
try {
...
Fragment f = (Fragment)clazz.getConstructor().newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.setArguments(args);
}
return f;
} catch(error e){
...
}
}
三、小结
初始化Fragment时如果需要传递参数,必须使用setArguments方法,才能保证Fragment不会丢失数据;同时初始化传参的过程最好封装成newInstance()静态方法方法。
本文主要参考了该篇博客,该博客介绍的更详细,源码和示例图都展示得比较完整