43

Hi I was looking at the following Fragments example on the android site.

http://developer.android.com/guide/components/fragments.html#Example

I would like to know why certain methods are performed.

Why for instance, in the detailsFragment is the following method performed:

public static DetailsFragment newInstance(int index) {
    DetailsFragment f = new DetailsFragment();

    // Supply index input as an argument.
    Bundle args = new Bundle();
    args.putInt("index", index);
    f.setArguments(args);

    return f;
}

Could you not also simply instantiate the DetailsFragment and use a setter method to set index instead. Bypassing the whole setArguments.

What's the point of using setArguments in the first place? Could you not just use setters and getters?

HGPB
  • 4,346
  • 8
  • 50
  • 86
  • 3
    Recently it's become common for an application's core functionality to be encapsulated in `Fragments`, and then have `Activities` essentially manage the arrangement of (and navigation between) screens composed of said fragments. With an `Activity`, you could pass a `Bundle` of extras in an intent and have access to that right away starting with `onCreate()`. `Fragments` don't respond to intents, so instead you can use `setArguments()` to supply it a `Bundle` "of extras" before it gets created. – Karakuri Jul 09 '12 at 15:52
  • @Karakuri thanks that's useful to know. – HGPB Jul 09 '12 at 16:02
  • 1
    Have a look at this one: http://stackoverflow.com/a/7160253/334493 – Benoit Duffez Jul 31 '12 at 07:52
  • possible duplicate of [Member variables vs setArguments in Fragments](http://stackoverflow.com/questions/6677136/member-variables-vs-setarguments-in-fragments) – tir38 May 12 '15 at 21:56

4 Answers4

40

You can use getters and setters, but by passing in a bundle you don't need to write that code, since it's already there. Also, I believe that these arguments are automatically passed in again if the screen orientation changes, which also makes life easier.

Essentially, setArguments and getArguments is just a design pattern that Google suggests you follow:

Every fragment must have an empty constructor, so it can be instantiated when restoring its activity's state. It is strongly recommended that subclasses do not have other constructors with parameters, since these constructors will not be called when the fragment is re-instantiated; instead, arguments can be supplied by the caller with setArguments(Bundle) and later retrieved by the Fragment with getArguments(). http://developer.android.com/reference/android/app/Fragment.html

I take that to include setters which are needed for your Fragment to operate as well. Then again - there's nothing forcing you to do it this way, and as you know - it's not the only way things could be made to work.

Matthew Runo
  • 1,387
  • 3
  • 20
  • 43
  • Good stuff, just two different ways to do the same job - fine. Your second point makes the use of setArguments valuable over just using setters and getters if that is true. In this case I'm not sure it would make any difference though. But I could be wrong. – HGPB Jul 09 '12 at 14:42
  • How about two constructors ; one empty, and one that accepts the initial state of the fragment. A fragment can then use the bundle passed in onSaveInstanceState() and onCreate() to keep instance state? – Glenn Bech Nov 28 '13 at 14:19
  • Glenn, normally what I do is have a static getInstance(..) method that creates a bundle with all the arguments and uses setArguments() on a new instance of the fragment. That way you have an easy "constructor" to call, the arguments get set, and Android has a nice empty constructor that it can use internally. – Matthew Runo Apr 24 '14 at 16:24
  • You're missing the point about fragment lifecycle. See @JohnnyLambada's answer. – enl8enmentnow Oct 11 '16 at 21:38
25

Just to add to Matthew's answer: he quoted correctly that Fragments need to have an empty constructor, so that the framework can re-instantiate them when needed.

It is fine to use getters and setters, but as the framework may destroy and re-create your Fragment, you must ensure to not lose those parameters.

This must be done via Fragment.onSaveInstanceState(). The saved stated will be passed back to you as the parameter savedInstanceState in Fragment.onCreate(), Fragment.onCreateView() and several other methods.

Using Fragment.setArguments() is (in most cases, I assume) easier, at the framework will automatically preserve the arguments and thus will do most of the work for you.

Setters may be the way to go for parameters you supply to the Fragment initially and which the fragment may adjust itself over time. Dealing with the savedInstanceState alone may be easier in this case than dealing with savedInstanceState and arguments - where you have to make a decision which is the valid parameter.

JohnnyLambada
  • 12,700
  • 11
  • 57
  • 61
sstn
  • 3,050
  • 19
  • 32
  • 4
    This is a critically important aspect of understanding Fragments that I feel may be grotesquely under-documented. Your response provides some insight. If you don't want to use setArguments, and instead want to use a setter, then you MUST use onSaveInstanceState or android will not be able to re-initialize your Fragment? Jeez! – rmirabelle Jul 01 '13 at 14:05
  • 3
    @rmirabelle Underdocumentation seems to be the case to me for a lot of cases in Android, unfortunately. I discovered a lot of cases which are not possible or problematic and which are either not documented at all or only as a side-node somewhere or stackoverflow/google groups answer somewhere. – sstn Jul 05 '13 at 09:51
6
public void setArguments (Bundle args)

Supply the construction arguments for this fragment. This can only be called before the fragment has been attached to its activity; that is, you should call it immediately after constructing the fragment. The arguments supplied here will be retained across fragment destroy and creation (may be the text in bold was missing from official documentation previously)

Fragments.setArguments(Bundle args)

Akh
  • 5,961
  • 14
  • 53
  • 82
1

In addition setters can be misused. If updateSomeOtherStuff() will change some view this will crash.

public class MyFragment extends Fragment {
   void setData(someData){
       this.someData = someData;
       updateSomeOtherStuff()
   }
}

If one passing in a bundle it is not possible to misuse the setter and you will always know that this will be set within the lifecycle methods.

Rene B.
  • 101
  • 6