Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member variables vs setArguments in Fragments

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?

like image 540
oobayly Avatar asked Jul 13 '11 09:07

oobayly


People also ask

Do arguments on fragments survive after a configuration change?

Fragments suffer the same process. After a configuration change, all the objects are going to be created again. The old objects will be cannon fodder for the Garbage Collector and the new ones won't keep the state the others have.

How do you use Getarguments in activity?

So one activity will create an Intent and put some extras in it, then call startActivity() and pass in in the intent. Another activity will use getIntent() to get a reference to the intent that the other activity prepared and can pull out the various extras.


2 Answers

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.

like image 144
Philipp Reichart Avatar answered Sep 20 '22 16:09

Philipp Reichart


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

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

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

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

Huh????

Amazing, but true. All of this creating Bundles with setArguments() madness exists to compensate for the need of a parameter-less Fragment constructor.

In short, I'm using the static newInstance method to create my 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     } } 
like image 43
rmirabelle Avatar answered Sep 21 '22 16:09

rmirabelle