如何向一个Fragment传递参数---setArguments方法的介绍
2017-06-01 19:02
435 查看
转载自 http://blog.csdn.net/small_lee/article/details/50553881
在我们平常开发中经常会用到Fragment,当我们使用Fragment时一般是通过new Fragment的构造方法来实现,如果我问你怎么向一个Fragment传递参数,你是不是会首先想到通过构造方法,当面试被问到这个问题的时候我也是这么想的,后来发现自己错了,现在给大家讲一下究竟该怎么做。
首先我们看构造方法这种方式为什么不行,根据Android文档说明,当一个fragment重新创建的时候,系统会再次调用 Fragment中的默认构造函数。 注意这里:是 默认构造函数。
这句话更直白的意思就是:当你小心翼翼的创建了一个带有重要参数的Fragment的之后,一旦由于什么原因(横竖屏切换)导致你的Fragment重新创建。——-很遗憾的告诉你,你之前传递的参数都不见了,因为recreate你的Fragment的时候,调用的是默认构造函数。
首先我们通过构造函数来传递参数,代码如下
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
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方法:
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
可以看到,屏幕旋转以后参数也保留下来了。
接下来我们通过源码看看Bundle这个参数到底如何保留下来的,
点进去Fragment的setArguments方法:
2
3
4
5
6
首先将当前的bundle对象赋值给一个全局的mArguments对象,然后我们看这个mAruments对象在哪里用到了
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方法
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之前使用。
在我们平常开发中经常会用到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之前使用。
相关文章推荐
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 如何向一个Fragment传递参数---setArguments方法的介绍
- 如何向一个Fragment传递参数---setArguments方法的介绍
- Objective-C中一个方法如何传递多个参数的理解
- Objective-C 一个方法如何传递多个参数?
- 我对Objective-C中一个方法如何传递多个参数的理解
- Objective-C中一个方法如何传递多个参数的理解
- Fragment中传递参数推荐用Fragment.setArguments(Bundle bundle),而不用构造方法。
- JSP页面间传递参数方法介绍
- Objectc-c方法如何传递多个参数
- android fragment传递参数_fragment之间传值的两种方法
- Fragment参数传递——setArguments
- Android解惑 - 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
- 利用NSInvocation给NSObject添加一个分类方法,解决传递多参数问题
- Jsp中通过get方法传递参数为中文时出现乱码如何解决?
- 求教:WebService如何传递一个TreeView类型的参数啊?
- Android Fragment传递参数_Fragment之间传值的两种方法
- Android解惑 - 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
- 一个内核模块例子(实现调用其他模块中的方法,传递参数等)