Java – Member variables vs setArguments in Fragments

androidandroid-fragmentscoding-stylejava

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:

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

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.

Any thoughts?

Best Answer

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

  • If it's in a Bundle the 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 Bundle of an Activity as-is to a Fragment embedded in the layout; e.g. I often use this when I have an Activity that displays a Fragment "fullscreen" and needs some ID (or ContentProvider URI) 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 Fragment close to that of an Activity, i.e. Bundle as "input parameters, no exceptions".

As for the downsides you mentioned:

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

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

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