成员变量与片段中的setArguments

时间:2011-07-13 09:59:17

标签: java android coding-style android-fragments

我注意到在片段的Android参考中(特别是DialogFragment),他们做了一些与我期望的不同的事情:

1)。使用public static foo newInstance()方法而不是构造函数 2)。使用setArguments而不是成员变量将值传递给onCreateDialog。

我已经读过使用反射时newInstance似乎是首选。但是我真的不明白为什么他们通过捆绑传递参数。虽然使用成员变量会更安全(不使用字符串从地图中获取)并且开销会更少。

有什么想法吗?

4 个答案:

答案 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()方法,我认为它们是封装newsetArguments()调用Fragment的简单方法;我有时会提供额外的MyFragment newInstance(String singleIdOfWhatToDisplay),同时创建BundleFragment并返回准备好的Fragment实例。

答案 1 :(得分:18)

我发现这是一个非常令人困惑的问题(许多人在Android环境中乱丢)。

setArguments()是一种解决方法,因为Android非常无用,需要为Fragments提供无参数构造函数。

我的困惑波澜起伏。首先,您在Fragment中自然覆盖的方法(例如onCreateonCreateView)会收到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创建,则参数不能很好地工作。我真的很讨厌这个。