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 而不是实例字段有一些优势:

1234563 .这样一来,内存不足的杀戮狂欢或最终的方向变化就不会丢失任何争论(这经常让我在旋转较少的模拟器中开发后第一次部署到真实设备时感到震惊)。

您可以将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() 方法,我认为它们是封装newsetArguments() 对我的Fragment 调用的简单方法;我有时会提供一个额外的MyFragment newInstance(String singleIdOfWhatToDisplay),它可以一次性创建BundleFragment,并返回一个准备就绪的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 中自然覆盖的方法(例如onCreateonCreateView)会收到一个Bundle 参数,该参数代表savedInstanceStatesavedInstanceState。这个实例状态显然与您通过setArguments() 存储并通过getArguments() 检索的值有任何关系。两者都使用BundleBundles 都可能在相同的覆盖方法中被访问,彼此没有任何关系。

其次,尚不清楚 Android 如何使用setArguments()。 Android 调用您的无参数构造函数以在旋转时重建您的Fragment,但显然也将调用构造Fragment 时最后调用的setArguments() 方法。

啊????

惊人,但真实。所有这些创建 BundlessetArguments() 的疯狂行为都是为了弥补对无参数 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的主要内容,如果未能解决你的问题,请参考以下文章

向Fragment传递参数,为什么用setArgument(),而不自定义变量再set赋值?

成员变量与局部变量

JAVA中的成员变量与局部变量

为什么C ++允许类成员函数中的局部变量与成员变量同名?

成员变量与局部变量的区别

C++类中的静态成员变量与静态成员函数的使用