Android解惑 - 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
Android解惑 - 为什么要用Fragment.setArguments(Bundle bundle)来传递参数
Fragment在Android3.0开始提供,并且在兼容包中也提供了Fragment特性的支持。Fragment的推出让我们编写和管理用户界面更快捷更方便了。
但当我们实例化自定义Fragment时,为什么官方推荐Fragment.setArguments(Bundle bundle)这种方式来传递参数,而不推荐通过构造方法直接来传递参数呢? 为了弄清这个问题,我们可以做一个测试,分别测试下这两种方式的不同
首先,我们来测试下通过构造方法传递参数的情况
public class FramentTestActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new TestFragment("param")).commit();
}
} public static class TestFragment extends Fragment { private String mArg = "non-param";
public TestFragment() {
Log.i("INFO", "TestFragment non-parameter constructor");
}
public TestFragment(String arg){
mArg = arg;
Log.i("INFO", "TestFragment construct with parameter");
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
TextView tv = (TextView) rootView.findViewById(R.id.tv);
tv.setText(mArg);
return rootView;
}
}}
可以看到我们传递过来的数据正确的显示了,现在来考虑一个问题,如果设备配置参数发生变化,这里以横竖屏切换来说明问题,显示如下
发生了什么问题呢?我们传递的参数哪去了?为什么会显示默认值?不急着讨论这个问题,接下来我们来看看Fragment.setArguments(Bundle bundle)这种方式的运行情况
public class FramentTest2Activity extends ActionBarActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout. activity_main); if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id. container, TestFragment.newInstance("param")).commit();}}public static class TestFragment extends Fragment { private static final String ARG = "arg"; public TestFragment() {
Log. i("INFO", "TestFragment non-parameter constructor" );} public static Fragment newInstance(String arg){
TestFragment fragment = new TestFragment();
Bundle bundle = new Bundle();
bundle.putString( ARG, arg);
fragment.setArguments(bundle);
return fragment;} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout. fragment_main, container,
false);
TextView tv = (TextView) rootView.findViewById(R.id. tv);
tv.setText(getArguments().getString( ARG));
return rootView;}}}
我们再来看看横竖屏切换后的运行情况
看到了吧,我们传递的参数在横竖屏切换的情况下完好保存了下来,正确的显示给用户
那么这到底是怎么回事呢,我们知道设备横竖屏切换的话,当前展示给用户的Activity默认情况下会重新创建并展现给用户,那依附于Activity的Fragment会进行如何处理呢,我们可以通过源码来查看
先来看看Activity的onCreate(Bundle saveInstance)方法
protected void onCreate(Bundle savedInstanceState) { if (DEBUG_LIFECYCLE ) Slog.v( TAG, "onCreate " + this + ": " + savedInstanceState); if (mLastNonConfigurationInstances != null) { mAllLoaderManagers = mLastNonConfigurationInstances .loaders ; } if (mActivityInfo .parentActivityName != null) { if (mActionBar == null) { mEnableDefaultActionBarUp = true ; } else { mActionBar .setDefaultDisplayHomeAsUpEnabled( true); } } if (savedInstanceState != null) { Parcelable p = savedInstanceState.getParcelable( FRAGMENTS_TAG ); mFragments .restoreAllState(p, mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances .fragments : null); } mFragments .dispatchCreate(); getApplication().dispatchActivityCreated( this , savedInstanceState); mCalled = true ; }
由于我们的Fragment是由FragmentManager来管理,所以可以跟进FragmentManager.restoreAllState()方法,通过对当前活动的Fragmnet找到下面的代码块
for (int i=0; i<fms.mActive.length; i++) {FragmentState fs = fms.mActive[i];if (fs != null) {Fragment f = fs.instantiate(mActivity, mParent);if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);mActive.add(f);// Now that the fragment is instantiated (or came from being// retained above), clear mInstance in case we end up re-restoring// from this FragmentState again.fs.mInstance = null;} else {mActive.add(null);if (mAvailIndices == null) {mAvailIndices = new ArrayList<Integer>();}if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);mAvailIndices.add(i);} }
接下来我们可以看看FragmentState.instantitate()方法的实现
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 ;
}
可以看到最终转入到Fragment. instantitate()方法
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); } }
通过此方法可以看到,最终会通过反射无参构造实例化一个新的Fragment,并且给mArgments初始化为原先的值,而原来的Fragment实例的数据都丢失了,并重新进行了初始化
通过上面的分析,我们可以知道Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过 Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。所以尽量使用 Fragment.setArguments(Bundle bundle)方式来传递参数
Android解惑 - 为什么要用Fragment.setArguments(Bundle bundle)来传递参数相关推荐
- Android Fragment传递参数Fragment.setArguments(Bundle bundle)
Fragment在Android3.0开始提供,并且在兼容包中也提供了Fragment特性的支持.Fragment的推出让我们编写和管理用户界面更快捷更方便了. 但当我们实例化自定义Fragment时 ...
- Fragment.setArguments()
在我们平常开发的时候Fragment是经常使用的,而我们创建一个Fragment对象的时候一般都会 通过 new Fragment()构造方法来实现,如果要传递参数我们一般会重载构造方法,例如 new ...
- Android常用控件之Fragment仿Android4.0设置界面
Fragment是Android3.0新增的概念,是碎片的意思,它和Activity很相像,用来在一个Activity中描述一些行为或部分用户界面:使用多个Fragment可以在一个单独的Activi ...
- android viewpager fragment传值,Android开发中如何解决Fragment +Viewpager滑动页面重复加载的问题...
前言 之前在做一个Viewpager上面加载多个Fragment时总会实例化已经创建好的Fragmnet对象类似 viewPager.setAdapter(new FragmentPagerAdapt ...
- android fragment界面滑动切换效果,Android App中使用ViewPager+Fragment实现滑动切换效果...
在android应用中,多屏滑动是一种很常见的风格,没有采用viewpager的代码实现会很长,如果采用ViewPager,代码就会短很多,但是使用ViewPager也有弊端:需要导入android- ...
- android fragment传递参数_fragment之间传值的两种方法
在Activity中加载Fragment的时候.有时候要使用多个Fragment切换.并传值到另外一个Fragment.也就是说两个Fragment之间进行参数的传递.查了很多资料.找到两种方法.一种 ...
- Android Studio初学者实例:Fragment学习--仿美团外卖界面
本次课程为Fragment为主题,课程的示例仿美团外卖界面,不同于底部导航栏的Fragment案例,此界面分为左侧切换与顶部切换.本文先是发布代码与效果,后续讲解将会在后续补充.先看看效果: 首先是布 ...
- Android studio实现底部导航,Android 开发之BottomBar+ViewPager+Fragment实现炫酷的底部导航效果...
BottomBar BottomBar是Github上的一个开源框架,因为从1.3.3开始不支持fragments了,要自己配置,弄了很久,不管是app的fragment还是V4 的程序总是总是闪退. ...
- Android开发之fragment传递参数的两种方法
非常简单一种是通过bundle,另外一种是通过fragment提供的instantiate(过时方法),都是kotlin版本,直接上代码吧: 方法一: //fragment传递参数方法一val fra ...
最新文章
- android+邮箱删除邮件,在Android上删除烦人的语音邮件通知 | MOS86
- JavaScript[对象.属性]集锦
- 控制语句 for while if switch
- 人才迁徙潮,2019年互联网各梯队排名重组,最适合程序员去的互联网公司有哪些?...
- dst matlab,DSTcode DST跟踪算法MATLAB代码,复杂环境中仿多目标 实现的单 Other systems 其他 272万源代码下载- www.pudn.com...
- 解决com.alibaba.fastjson.JSONException: autoType is not support
- Java支持的编码格式
- [USACO5.1] Musical Themes
- 浅谈Kotlin(四):控制流
- 行测测评——矩阵、圆形、环形三角图形数列推理解题技巧
- 电视hdr测试软件,HDR+4K一个都不能少 本地资源播放测试
- 浅析Minecraft直播弹幕模组BakaDanmaku源码
- c++创建一个linux deamon进程
- 2019.05 随笔
- cpu之RegDst_Ins
- 为什么Google是人工智能发展的主要动力?
- 苏宁低调内测“宁互宝”,网络互助成巨头必争之地...
- 梯度下降,随机梯度下降,代码实现
- Git 修改已提交的 commit 信息
- 贝壳后台开发面经(22 届春招)