Member variables vs setArguments in Fragments
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.@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 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 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.
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
}
}