我注意到在片段的Android参考中(特别是DialogFragment),他们做了一些与我期望的不同的事情:
1)。使用public static foo newInstance()
方法而不是构造函数
2)。使用setArguments而不是成员变量将值传递给onCreateDialog。
我已经读过使用反射时newInstance似乎是首选。但是我真的不明白为什么他们通过捆绑传递参数。虽然使用成员变量会更安全(不使用字符串从地图中获取)并且开销会更少。
有什么想法吗?
答案 0 :(得分:47)
我也偶然发现了这一点,发现在实例字段上使用参数Bundle
有一些好处:
如果它在Bundle
中,Android系统知道它并且可以创建和销毁您的Fragment
(使用强制无参数/默认构造函数和常用生命周期方法),并且只是传入参数再次捆绑。这样,在低内存消除狂欢或最终的方向更改时,没有任何参数会丢失(在旋转较少的模拟器中进行开发后,这通常会在首次部署到真实设备时受到影响)。
您可以将Bundle
的附加内容Activity
原样传递给布局中嵌入的Fragment
;例如我经常使用Activity
显示Fragment
“全屏”并需要一些ID(或ContentProvider
URI)才能知道要显示/执行的操作。在我传递之前,有时甚至会向Bundle
(或副本)添加更多内容,例如。
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) { // not a re-creation
final Bundle args = new Bundle(getIntent().getExtras());
args.putInt(CoverImageFragment.BACKGROUND_RESOURCE, android.R.color.black);
final Fragment fragment = CoverImageFragment.newInstance(args);
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, fragment)
.commit();
}
}
它保持了Fragment
接近Activity
的方式,即Bundle
作为“输入参数,没有例外”。
至于你提到的缺点:
我认为开销很小,因为您很可能不会在紧急循环中查询Bundle
,因此在onCreate()
onViewCreate()
中将您的参数数据输出一次等等并不是那么糟糕。
对于类型安全,Bundle
具有所有不同的getXXXX()
方法,甚至重载,以便在缺少某些内容/可选时提供默认值:)
对于newInstance()
方法,我认为它们是封装new
和setArguments()
调用Fragment
的简单方法;我有时会提供额外的MyFragment newInstance(String singleIdOfWhatToDisplay)
,同时创建Bundle
和Fragment
并返回准备好的Fragment
实例。
答案 1 :(得分:18)
我发现这是一个非常令人困惑的问题(许多人在Android环境中乱丢)。
setArguments()
是一种解决方法,因为Android非常无用,需要为Fragments提供无参数构造函数。
我的困惑波澜起伏。首先,您在Fragment
中自然覆盖的方法(例如onCreate
,onCreateView
)会收到Bundle
参数,该参数代表savedInstanceState
Fragment
}。对于您通过setArguments()
存储的值并通过getArguments()
检索,此实例状态显然具有 NOTHING 。两者都使用Bundle
,两个Bundles
都可能在同一个重写方法中访问,两者都没有任何关系。
其次,目前还不清楚Android如何使用setArguments()
。 Android会调用您的无参数构造函数来重新构建旋转时的Fragment
,但显然ALSO将调用setArguments()
构造时最后调用的Fragment
方法。
咦????
太棒了,但也是如此。所有这些创建Bundles
setArguments()
疯狂都存在,以弥补无参数Fragment
构造函数的需要。
简而言之,我使用静态newInstance
方法创建我的Fragment
。
public MyFragment() {
//satisfy Android
}
public static MyFragment newInstance(long record_id) {
Log.d("MyFragment", "Putting " + record_id + " into newInstance");
MyFragment f = new MyFragment();
Bundle args = new Bundle();
args.putLong("record_id", record_id);
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* Perform an immediate check of arguments,
* which ARE NOT the same as the bundle used
* for saved instance state.
*/
Bundle args = getArguments();
if(args != null) {
record_id = args.getLong("record_id");
Log.d("MyFragment", "found record_id of " + String.valueOf(record_id));
}
if(savedInstanceState != null) {
//now do something with savedInstanceState
}
}
答案 2 :(得分:9)
我对Android编程很陌生,但这是我目前对该问题的理解:
Fragments 的构造函数不能具有任何参数。当您的活动暂停时,您的片段可以被释放。在恢复活动之前,系统会创建一个新版本的Fragment来调用构造函数。如果使用非默认构造函数,Android如何知道Fragments构造函数的参数的类型和值是什么?
我不相信捆绑被释放。该包保持精确,以便在使用默认构造函数重新创建它后可以将其传递回Fragment。
Philipp Reichart在他的帖子中实现了这一点(实际上已经超过了。)
答案 3 :(得分:2)
只是想为参数添加一个缺点就是你必须动态创建片段。如果从xml创建,则参数不能很好地工作。我真的很讨厌这个。