java Fragment 中的成员变量与 setArguments

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6677136/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:53:26  来源:igfitidea点击:

Member variables vs setArguments in Fragments

javaandroidcoding-styleandroid-fragments

提问by oobayly

I've noticed that in the Android reference for Fragments (notably DialogFragment) that they do a couple of things different from what I'd expect:

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

1). Use public static foo newInstance()method rather than a constructor.
2). Pass values to onCreateDialog using setArguments rather than member variables.

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

I've read that newInstance appears to be preferrable when using reflection. However I really don't understand why they're passing parameters via a bundle. I'd have though using member variables would be safer (not using a string to fetch from a map) and would have less of an overhead.

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

Any thoughts?

有什么想法吗?

回答by Philipp Reichart

I've also stumbled upon this and found a few advantages to using the arguments Bundleover instance fields:

我也偶然发现了这一点,并发现了Bundle在实例字段上使用参数的一些优势:

  • If it's in a Bundlethe Android system knows about it and can create and destroy your Fragment(using the mandatory parameterless/default constructor and usual lifecycle methods), and just pass in the arguments bundle again. This way no arguments get lost on a low memory killing spree or the eventual orientation changes (this often hits me on first deploy to a real device after development in the less-rotating emulator).

  • You can just pass the extras Bundleof an Activityas-is to a Fragmentembedded in the layout; e.g. I often use this when I have an Activitythat displays a Fragment"fullscreen" and needs some ID (or ContentProviderURI) to know what to display/do. I sometimes even add more stuff to a Bundle(or a copy) before I pass it on, e.g.

    @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();
      }
    }
    
  • It keeps the way of developing a Fragmentclose to that of an Activity, i.e. Bundleas "input parameters, no exceptions".

  • 如果它在BundleAndroid 系统中知道它并且可以创建和销毁您的Fragment(使用强制性的无参数/默认构造函数和通常的生命周期方法),并且只需再次传入参数包。这样一来,就不会因为内存不足而导致混乱或最终方向发生变化(这通常会让我在在旋转较少的模拟器中开发后第一次部署到真实设备时感到震惊)。

  • 您可以BundleActivity原样的附加内容传递给Fragment嵌入在布局中的内容;例如,当我有一个Activity显示Fragment“全屏”并且需要一些 ID(或ContentProviderURI)来知道要显示/做什么时,我经常使用它。有时我什至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作为“输入参数,没有例外”。

As for the downsides you mentioned:

至于你提到的缺点:

  • I think the overhead is minimal because you most likely won't be querying the Bundlein a tight loop, so getting your argument data out once in onCreate(), onViewCreate(), etc. isn't that bad.

  • For type-safety, Bundlehas all the different getXXXX()methods, and even overloads to provide a default value if a something is missing/optional :)

  • 我觉得开销是最小的,因为你很可能不会被查询Bundle在紧密循环,因此让你的论点的数据进行一次onCreate()onViewCreate()等是没有那么糟糕。

  • 对于类型安全,Bundle具有所有不同的getXXXX()方法,甚至重载以在缺少某些内容/可选时提供默认值:)

As for the newInstance()methods, I think of them as an easy way to encapsulate the newand setArguments()calls for my Fragment; I sometimes provide an additional MyFragment newInstance(String singleIdOfWhatToDisplay)that creates both the Bundleand Fragmentin one go and returns a ready-to-go Fragmentinstance.

至于newInstance()方法,我认为它们是封装newsetArguments()调用 my的简单方法Fragment;我有时会提供一个额外的MyFragment newInstance(String singleIdOfWhatToDisplay),一次性创建BundleFragment并返回一个准备就绪的Fragment实例。

回答by rmirabelle

I found this to be a HIGHLY confusing issue (one of many that litter the Android landscape).

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

setArguments()is a workaround for Android's very unhelpful need to have a parameter-less constructor available for Fragments.

setArguments()是 Android 需要为 Fragment 提供无参数构造函数的非常无益的解决方法。

My confusion came in waves. First, the methods you naturally override in your Fragment(e.g. onCreate, onCreateView) receive a Bundleparameter that represents the savedInstanceStateof your Fragment. This instance state apparently has NOTHINGwhatsoever to do with the values you store via setArguments()and retrieve via getArguments(). Both use a Bundle, both Bundlesare likely to be accessed within the same overridden method, neither have anything to do with each other.

我的困惑如潮水般涌来。首先,你在你的自然覆盖的方法Fragment(例如onCreateonCreateView)收到一个Bundle表示该参数savedInstanceState你的Fragment。此实例状态显然与您通过 存储和检索的值没有任何关系。两者都使用 a ,两者都可能在同一个被覆盖的方法中访问,彼此之间没有任何关系。setArguments()getArguments()BundleBundles

Second, it's unclear how Android uses setArguments(). Android calls your parameter-less constructor to rebuild your Fragmenton rotate, but apparently ALSO will call whichever setArguments()method was last called when the Fragmentwas constructed.

其次,目前还不清楚 Android 如何使用setArguments(). Android 调用您的无参数构造函数来重建您Fragment的旋转,但显然也将调用构造setArguments()时最后调用的任何方法Fragment

Huh????

咦???

Amazing, but true. All of this creating Bundleswith setArguments()madness exists to compensate for the need of a parameter-less Fragmentconstructor.

惊人,但真实。所有这些疯狂的创建Bundles都是setArguments()为了弥补对无参数Fragment构造函数的需求。

In short, I'm using the static newInstancemethod to create my 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
    }
}

回答by WayneJ

I am pretty new to Android programming but this is my current understanding of the issue:

我对 Android 编程很陌生,但这是我目前对这个问题的理解:

The constructor for Fragments cannothave any parameters. When your activity is paused your Fragment can be released. Before your activity is resumed, the system creates a new version of your Fragment calling the constructor. If a non-default constructor is used, how is Android supposed to know what the types and values are for the arguments to your Fragments constructor?

Fragments 的构造函数不能有任何参数。当您的活动暂停时,您的 Fragment 可以被释放。在您的活动恢复之前,系统会调用构造函数创建一个新版本的 Fragment。如果使用非默认构造函数,Android 应该如何知道 Fragments 构造函数的参数的类型和值是什么?

I don't believe that bundle is released. The bundle is kept around precisely so that it can be passed back to your Fragment after it has been recreated with the default constructor.

我不相信该捆绑包已发布。该包被精确地保留,以便它可以在使用默认构造函数重新创建后传递回您的 Fragment。

Philipp Reichart eluded to this in his post (actually more than eluded.)

Philipp Reichart 在他的帖子中回避了这一点(实际上不仅仅是回避。)

回答by havexz

Just want to add one more drawback to arguments is that you have to dynamically create fragments. As arguments does not work very well if you creating from the xml. And I really hate that.

只是想为参数添加另一个缺点是您必须动态创建片段。如果您从 xml 创建参数,则参数不会很好地工作。我真的很讨厌那样。