如何向一个Fragment传递参数---setArguments方法的介绍
来源:互联网 发布:数据研究中心美国大学 编辑:程序博客网 时间:2024/05/17 22:23
在我们平常开发中经常会用到Fragment,当我们使用Fragment时一般是通过new Fragment的构造方法来实现,如果我问你怎么向一个Fragment传递参数,你是不是会首先想到通过构造方法,当面试被问到这个问题的时候我也是这么想的,后来发现自己错了,现在给大家讲一下究竟该怎么做。
首先我们看构造方法这种方式为什么不行,根据Android文档说明,当一个fragment重新创建的时候,系统会再次调用 Fragment中的默认构造函数。 注意这里:是 默认构造函数。
这句话更直白的意思就是:当你小心翼翼的创建了一个带有重要参数的Fragment的之后,一旦由于什么原因(横竖屏切换)导致你的Fragment重新创建。——-很遗憾的告诉你,你之前传递的参数都不见了,因为recreate你的Fragment的时候,调用的是默认构造函数。
首先我们通过构造函数来传递参数,代码如下
public class MainActivity extends FragmentActivity { private FragmentManager manager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); manager = getSupportFragmentManager(); /* * 这里为什么要进行空判断,因为在屏幕旋转的时候,系统会执行onSaveInstanceState * 方法去保存当前activity的状态,然后activity会重建,执行onCreate方法,如果我们不判断 * savedInstanceState是否为空,那么每次就会执行下面的commit操作,向Fragmnet传递参数, * 这样参数的却会保留下来,但是我们不应该每次都去传递参数。当进行了空判断时,当Activity重建 * 的时候,会调用Fragment的默认构造函数,所以我们传递过去的参数不能保留了。 */ if(savedInstanceState == null){ manager.beginTransaction().replace(R.id.fl_main, new FragmentOne("params")).commit(); } } @Override protected void onSaveInstanceState(Bundle outState) { System.out.println("=========savedInstanceState "); super.onSaveInstanceState(outState); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
public class FragmentOne extends Fragment { private TextView textView; private String params = "default"; public FragmentOne(){ System.out.println("===========default constructor"); } /** * 通过构造方法接收传递过来的参数 * @param content */ public FragmentOne(String content){ params = content; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment1, container,false); textView = (TextView) view.findViewById(R.id.textview); textView.setText(params); return view; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
可以看到此时传递过来的参数已经不见了,说明通过构造方法传递参数是不行的。
我们看看控制台的打印
注意:
这里我们必须写出默认的构造函数,因为Fragment重建的时候,会调用默认的构造函数,也就是空参数的构造函数,如果我们只是给出了带参数的构造函数,系统是不会为我们创建空参数的构造函数的,如果你不写,在Fragment重建的时候就会发生下面的错误。
接下来看看官方推荐的setArguments方法:
public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .replace(R.id.fl_main, FragmentOne.newInstance("params")) .commit(); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
public class FragmentOne extends Fragment{ private TextView textView; public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_one, null); textView = (TextView) view.findViewById(R.id.textview); if(getArguments()!=null){ //取出保存的值 textView.setText(getArguments().getString("name")); } return view; } public static FragmentOne newInstance(String text){ FragmentOne fragmentOne = new FragmentOne(); Bundle bundle = new Bundle(); bundle.putString("name", text); //fragment保存参数,传入一个Bundle对象 fragmentOne.setArguments(bundle); return fragmentOne; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
可以看到,屏幕旋转以后参数也保留下来了。
接下来我们通过源码看看Bundle这个参数到底如何保留下来的,
点进去Fragment的setArguments方法:
public void setArguments(Bundle args) { if (mIndex >= 0) { throw new IllegalStateException("Fragment already active"); } mArguments = args; }
- 1
- 2
- 3
- 4
- 5
- 6
首先将当前的bundle对象赋值给一个全局的mArguments对象,然后我们看这个mAruments对象在哪里用到了
public Fragment instantiate(Activity activity, Fragment parent) { if (mInstance != null) { return mInstance; } if (mArguments != null) { mArguments.setClassLoader(activity.getClassLoader()); } //重点在这里 mInstance = Fragment.instantiate(activity, mClassName, mArguments); if (mSavedFragmentState != null) { mSavedFragmentState.setClassLoader(activity.getClassLoader()); mInstance.mSavedFragmentState = mSavedFragmentState; } mInstance.setIndex(mIndex, parent); mInstance.mFromLayout = mFromLayout; mInstance.mRestored = true; mInstance.mFragmentId = mFragmentId; mInstance.mContainerId = mContainerId; mInstance.mTag = mTag; mInstance.mRetainInstance = mRetainInstance; mInstance.mDetached = mDetached; mInstance.mFragmentManager = activity.mFragments; if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, "Instantiated fragment " + mInstance); return mInstance; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
然后我们进入Fragment的instantiate方法
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, 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); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
这里通过无參反射构造了一个新的Fragment对象,然后把我们保存的Bundle对象传递给了新的Fragment对象的mAruments成员变量。通过上面的分析,我们就知道了为什么setArguments方法能够保留参数了。
注意:
setArguments方法的调用必须要在Fragment与Activity关联之前。
这句话可以这样理解,setArgument方法的使用必须要在FragmentTransaction 的commit之前使用。
原文链接:http://blog.csdn.net/small_lee/article/details/50553881
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 如何向一个Fragment传递参数---setArguments方法的介绍
- Fragment.setArguments()方法向fragment对象传递数据的重要作用
- Fragment参数传递——setArguments
- Fragment中传递参数推荐用Fragment.setArguments(Bundle bundle),而不用构造方法。
- Android Fragment传递参数Fragment.setArguments(Bundle bundle)
- Android Fragment传递参数Fragment.setArguments(Bundle bundle)
- 向Fragment传递参数
- 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
- 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
- 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
- Android使用newInstance()实例化fragment&setArguments()传递参数
- 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
- 如何向一个jsp传递两个以上的参数
- 如何向一个jsp传递两个以上的参数
- Fragment.setArguments()的初衷。
- [leetcode] 231. Power of Two
- 剑指offer题65
- fastText原理及应用
- #2017 Multi-University Training Contest
- 矩阵中的路径—递归
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 网页打开本地应用程序
- Java学习之ArrayList和LinkedList
- cartographer源码分析(21)-sensor-ordered_multi_queue.h
- ios 基础控件系列之 UIScrollView 初识
- xynu第二次比赛
- jsp基础
- CS231n课程笔记翻译9:卷积神经网络笔记
- 牛客三模-大数据方向:选择题和编程题