Android解惑 - 为什么要用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 {
@Override
protected 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;
}
}
}
我们再来看看横竖屏切换后的运行情况
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);
}
}
通过上面的分析,我们可以知道Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。所以尽量使用Fragment.setArguments(Bundle bundle)方式来传递参数
Android解惑 - 为什么要用Fragment.setArguments(Bundle bundle)来传递参数(转)的更多相关文章
- Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead
“Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(B ...
- Error:Error: Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead [ValidFragment]
原文博客链接:https://blog.csdn.net/chniccs/article/details/51258972 在创建fragment时,你可能在打包时碰到如下错误 Error:Error ...
- “Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle)instead”
“Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(B ...
- Android典型界面设计——ViewPage+Fragment实现区域顶部tab滑动切换
一.问题描写叙述 本系列将结合案例应用,陆续向大家介绍一些Android典型界面的设计,首先说说tab导航,导航分为一层和两层(底部区块+区域内头部导航).主要实现方案有RadioGroup+View ...
- android fragment传递参数_fragment之间传值的两种方法
在Activity中加载Fragment的时候.有时候要使用多个Fragment切换.并传值到另外一个Fragment.也就是说两个Fragment之间进行参数的传递.查了很多资料.找到两种方法.一种 ...
- Android常用控件之Fragment仿Android4.0设置界面
Fragment是Android3.0新增的概念,是碎片的意思,它和Activity很相像,用来在一个Activity中描述一些行为或部分用户界面:使用多个Fragment可以在一个单独的Activi ...
- 【Android 应用程序开发】 Fragment 详细说明
笔者 : 汉书亮 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38064191 本博客代码地址 : -- 单一 Fragmen ...
- [Android Pro] java.lang.IllegalStateException: Fragment(XXFragment) not attached to Activity异常
转载:http://blog.csdn.net/winson_jason/article/details/20357435 下边两个问题,是在开发中碰到的一些关于Fragment的偶发性的问题,今天时 ...
- 如何向一个Fragment传递参数---setArguments方法的介绍
在我们平常开发中经常会用到Fragment,当我们使用Fragment时一般是通过new Fragment的构造方法来实现,如果我问你怎么向一个Fragment传递参数,你是不是会首先想到通过构造方法 ...
随机推荐
- HDU4831&&4832&&4834
好久没打代码啦,今天lu一发百度之星,感觉还是学到不少东西的,写点收获. 第一题就是现在的HDU4831啦,题意很清楚,我一开始以为休息区也可以变为风景区,所以就不敢敲了,后来才得知数据里只会改风景区 ...
- SQL技术内幕-6 rank()over(order by XX COLLATE) 的用法
DECLARE @Names TABLE ( name VARCHAR(20) ); INSERT INTO @Names VALUES ('DeSzmetch'),('DESZMETCH'),('D ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- 为什么toString方法可以用来区分数组和对象?
首先大家都应该知道在javascript中只有是对象都存在toString方法,将调用该方法的值转换为字符串返回,如下: var arr = [1, 2, 3]; console.log(arr.to ...
- 利用securecrt在linux与windows之间传输文件
SecureCRT这款SSH客户端软件同时具备了终端仿真器和文件传输功能.比ftp命令方便多了,而且服务器不用再开FTP服务了.rz,sz是便是Linux/Unix同Windows进行ZModem文件 ...
- lintcode:线段树的查询
线段树的查询 对于一个有n个数的整数数组,在对应的线段树中, 根节点所代表的区间为0-n-1, 每个节点有一个额外的属性max,值为该节点所代表的数组区间start到end内的最大值. 为Segmen ...
- Android核心分析 之十Android GWES之基本原理篇
Android GWES基本框架篇 我这里的GWES这个术语实际上从Microsoft 的Window上移植过来的,用GWES来表示Android的窗口事件系统不是那么准确,在Android中Wind ...
- 虚拟机WindowServer2003共享文件夹
前话 之前我写过虚拟机装SQL Server的博文,也许有同学参考了也通过虚拟机装数据库服务来做实验作业了. 到了第二章节学习时,实验要求数据库导出Excel文件,这样一来就出现了小问题了,Windo ...
- asp.net+swfupload 多图片批量上传(附源码下载)
asp.net的文件上传都是单个文件上传方式,无法执行一次性多张图片批量上传操作,要实现多图片批量上传需要借助于flash,通过flash选取多个图片(文件),然后再通过后端服务进行上传操作. 本次教 ...
- 拥有更好性能的requesAnimationFrame(Better Performance with requestAnimationFrame)
介绍: 这篇文章讨论的是你可以(也应该)学习通过使用requestAnimationFrame API,而不是使用之前的setInterval/setTimeout方法,来提高动画的性能:如何使用re ...