Fragments 中的成员变量与 setArguments
Posted
技术标签:
【中文标题】Fragments 中的成员变量与 setArguments【英文标题】:Member variables vs setArguments in Fragments 【发布时间】:2011-10-04 08:43:21 【问题描述】:我注意到在 Fragments 的 android 参考资料(特别是 DialogFragment)中,它们做了一些与我预期不同的事情:
1)。使用public static foo newInstance()
方法而不是构造函数。
2)。使用 setArguments 而不是成员变量将值传递给 onCreateDialog。
我读到 newInstance 在使用反射时似乎更可取。但是我真的不明白他们为什么要通过包传递参数。虽然使用成员变量会更安全(不使用字符串从地图中获取)并且开销会更少。
有什么想法吗?
【问题讨论】:
【参考方案1】:我也偶然发现了这一点,并发现使用参数 Bundle
而不是实例字段有一些优势:
您可以将Activity
的额外Bundle
按原样传递给嵌入布局中的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
实例。
【讨论】:
newInstance 方法实现了什么构造函数无法实现的功能?我可以从构造函数调用setArguments
。
@Matthias 我认为在这些情况下创建工厂方法只是更好的风格......
newInstance 不是工厂方法(如在工厂方法模式中,如果这就是您的意思——请参阅en.wikipedia.org/wiki/Factory_method_pattern);它是静态的,因此不能被覆盖,对于它返回的类型也不是通用的。据我所知,除了个人喜好之外,它与直接使用构造函数相比没有任何优势。但是,我依稀记得 Fragments 需要一个默认的构造函数吗?也许这里的想法是不必定义 2 个 ctor,一个采用捆绑参数,一个为空。最佳猜测。
我不明白这一点。如果我们使用 setArguments,我们传递的 Bundle 会以某种方式保留吗?如何?当 Activity 和 Fragment 在旋转后重新创建时,为什么我们在宿主 Activity 中创建的 Bundle 会神奇地再次用于实例化 Fragment?除非用于实例化Fragment的Bundle本身是手动保存在Activity中的,否则在重新创建Activity时不会自然丢失吗?我仍然认为调用 setArguments 和在 Fragment 中编写 setter 之间没有区别。
@Levit 1) 我很确定参数包被保留了。来源:提供此片段的构造参数。这只能在片段附加到其活动之前调用;也就是说,您应该在构建片段后立即调用它。此处提供的参数将在片段销毁和创建过程中保留。【参考方案2】:
我发现这是一个非常令人困惑的问题(Android 环境中的众多问题之一)。
setArguments()
是解决 Android 非常无益的需要为 Fragments 提供无参数构造函数的解决方法。
我的困惑一波又一波。首先,您在Fragment
中自然覆盖的方法(例如onCreate
、onCreateView
)会收到一个Bundle
参数,该参数代表savedInstanceState
的savedInstanceState
。这个实例状态显然与您通过setArguments()
存储并通过getArguments()
检索的值有任何关系。两者都使用Bundle
,Bundles
都可能在相同的覆盖方法中被访问,彼此没有任何关系。
其次,尚不清楚 Android 如何使用setArguments()
。 Android 调用您的无参数构造函数以在旋转时重建您的Fragment
,但显然也将调用构造Fragment
时最后调用的setArguments()
方法。
啊????
惊人,但真实。所有这些创建 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
【讨论】:
【参考方案3】:我对 Android 编程很陌生,但这是我目前对该问题的理解:
片段的构造函数不能有任何参数。当您的活动暂停时,您的 Fragment 可以被释放。在您的活动恢复之前,系统会创建一个新版本的 Fragment 调用构造函数。如果使用非默认构造函数,Android 应该如何知道 Fragments 构造函数的参数的类型和值是什么?
我不相信该捆绑包已发布。该包被精确地保留,以便在使用默认构造函数重新创建它后可以将其传递回您的 Fragment。
Philipp Reichart 在他的帖子中回避了这一点(实际上不仅仅是回避。)
【讨论】:
您确定您是 Android 新手吗?这是一个简洁、精心设计的答案。【参考方案4】:只想给参数添加一个缺点是您必须动态创建片段。如果您从 xml 创建,因为参数不能很好地工作。我真的很讨厌这样。
【讨论】:
您可以使用getActivity().getIntent().getExtras()
从片段中访问活动参数,并且效果很好。
我认为要传递参数,您需要在代码中创建片段。如果您在 xml 中定义片段,我不记得有没有办法传递参数。有吗?
我正在尝试在我的 Fragment 的零参数构造函数中执行 setArguments(new Bundle()) 以解决无法在 xml 实例化片段中使用 get/setArguments 的问题。 以上是关于Fragments 中的成员变量与 setArguments的主要内容,如果未能解决你的问题,请参考以下文章