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?
I am pretty new to Android programming but this is my current understanding of the issue:
The constructor for Fragments cannot have 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?
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.
Philipp Reichart eluded to this in his post (actually more than eluded.)
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 yourFragment
(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 anActivity
as-is to aFragment
embedded in the layout; e.g. I often use this when I have anActivity
that displays aFragment
"fullscreen" and needs some ID (orContentProvider
URI) to know what to display/do. I sometimes even add more stuff to aBundle
(or a copy) before I pass it on, e.g.It keeps the way of developing a
Fragment
close to that of anActivity
, 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 inonCreate()
,onViewCreate()
, etc. isn't that bad.For type-safety,
Bundle
has all the differentgetXXXX()
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 thenew
andsetArguments()
calls for myFragment
; I sometimes provide an additionalMyFragment newInstance(String singleIdOfWhatToDisplay)
that creates both theBundle
andFragment
in one go and returns a ready-to-goFragment
instance.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 aBundle
parameter that represents thesavedInstanceState
of yourFragment
. This instance state apparently has NOTHING whatsoever to do with the values you store viasetArguments()
and retrieve viagetArguments()
. Both use aBundle
, bothBundles
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 yourFragment
on rotate, but apparently ALSO will call whicheversetArguments()
method was last called when theFragment
was constructed.Huh????
Amazing, but true. All of this creating
Bundles
withsetArguments()
madness exists to compensate for the need of a parameter-lessFragment
constructor.In short, I'm using the static
newInstance
method to create myFragment
.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.