781

I have seen two general practices to instantiate a new Fragment in an application:

Fragment newFragment = new MyFragment();

and

Fragment newFragment = MyFragment.newInstance();

The second option makes use of a static method newInstance() and generally contains the following method.

public static Fragment newInstance() 
{
    MyFragment myFragment = new MyFragment();
    return myFragment;
}

At first, I thought the main benefit was the fact that I could overload the newInstance() method to give flexibility when creating new instances of a Fragment - but I could also do this by creating an overloaded constructor for the Fragment.

Did I miss something?

What are the benefits of one approach over the other? Or is it just good practice?

AnV
  • 2,794
  • 3
  • 32
  • 43
Graham Smith
  • 25,627
  • 10
  • 46
  • 69
  • When there are parameters, there is no choice, and this is extensively answered here. Still, the question remains for no-argument construction of the fragment. – rds Dec 07 '15 at 10:51
  • 1
    After learning about factory pattern's and how a calling class not instantiating an object itself helps in decoupling them, I thought this would be a strong point for the newInstance() method. Am I wrong on this? I haven't seen this specific argument spoken of as a benefit. – Mobile Applications Nov 02 '16 at 02:30

16 Answers16

1255

If Android decides to recreate your Fragment later, it's going to call the no-argument constructor of your fragment. So overloading the constructor is not a solution.

With that being said, the way to pass stuff to your Fragment so that they are available after a Fragment is recreated by Android is to pass a bundle to the setArguments method.

So, for example, if we wanted to pass an integer to the fragment we would use something like:

public static MyFragment newInstance(int someInt) {
    MyFragment myFragment = new MyFragment();

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    myFragment.setArguments(args);

    return myFragment;
}

And later in the Fragment onCreate() you can access that integer by using:

getArguments().getInt("someInt", 0);

This Bundle will be available even if the Fragment is somehow recreated by Android.

Also note: setArguments can only be called before the Fragment is attached to the Activity.

This approach is also documented in the android developer reference: https://developer.android.com/reference/android/app/Fragment.html

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
yydl
  • 24,284
  • 16
  • 65
  • 104
  • 2
    Then they should have make newInstance() for us to override – urSus Jan 04 '13 at 03:09
  • 7
    @Vlasto unfortunately static methods can't be overridden. – AJD Feb 05 '13 at 15:08
  • 11
    @yydl I think I'm missing something here, couldn't you use a constructor here anyway, one that creates the Bundle and calls setArguments() still since it will only be called by your code (and not when Android re-creates your fragment)? – Mike Tunnicliffe Mar 30 '13 at 13:48
  • 1
    Ah, I see that lint gives a warning if you a non-default constructor. – Mike Tunnicliffe Mar 30 '13 at 13:52
  • 6
    This is also documented fairly well in the frag docs: http://developer.android.com/reference/android/app/Fragment.html#Fragment() – greg7gkb Apr 16 '13 at 17:53
  • 2
    Is there an advantage to using a Bundle here? Isn't it easier to just set the int value of myFragment straight away? e.g. myFragment.someInt = someInt; return myFragment; – mgibson Jun 27 '13 at 14:55
  • 10
    @mgibson You *must* use a bundle if you want the data to be available when the fragment is later recreated. – yydl Jun 30 '13 at 02:41
  • 3
    @yydl and what if you want to pass objects? should this be done using a thread instead? I've successfully passed objects from my main activity into 3 different fragments by accesors, but I'm afraid that at some point I'll get a null pointer even though the main activity is the parent activity. – Ben Sewards Jul 25 '13 at 13:10
  • 2
    @BenSewards Actually, the best way to do that would probably be to [implement Parcelable](http://developer.android.com/reference/android/os/Parcelable.html) and then putParcelable on the Bundle (you can also use Serializable, but it's not recommended) – yydl Jul 30 '13 at 16:46
  • 141
    Being FORCED to create a no-argument constructor for fragments is potentially the single biggest gotcha in all of programming, anywhere. It forces a complete paradigm shift in object creation and initialization. If you're new to Android and have stumbled on this thread, please read the answer above over and over and over again. – rmirabelle Aug 02 '13 at 15:20
  • It is possible to preserve the fragment and its data such as those passed to constructors by calling setRetainInstance(true). This method makes sure the fragment won't call onCreate and onDestroy at config change like orientation. http://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean – inmyth Sep 30 '13 at 17:30
  • 5
    @yydl great answer and i totally get the solution. You said "If Android decides to recreate your Fragment later". Could you give some examples or point to the documentation where Android does decide to do this? – KG - Oct 25 '13 at 17:57
  • @rmirabelle that's how a(ny) framework works, it give constraints on classes/objects it can work with. [`Activity.onCreate`](http://developer.android.com/reference/android/app/Activity.html#onCreate%28android.os.Bundle%29) instead of a constructor is similar not to mention [`afterPropertiesSet`](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/InitializingBean.html#afterPropertiesSet--) in Spring. You can try to implement a type-safe method of instantiating a class with an arbitrary constructor in Java, I don't think it's possible. – TWiStErRob Jul 28 '14 at 09:11
  • 13
    I would argue with that assertion. First, type-safeness is a language concern, not a framework concern. Secondly, IMO, the framework is stepping into the area of "things your API must never do". If I want to pass the library of congress into my fragment constructor, then I should be allowed to. The "no-args" constructor contract basically kills the use of dependency injection in fragments - major yuck. – rmirabelle Jul 28 '14 at 14:14
  • 4
    @fd I totally agree that a non-default constructor that initializes a Bundle and use `setArguments()` would do the trick too. You're not gonna use any parameter here anyway, but in onCreateView, so when the system creates the fragment with the default constructor (which you **have to** declare), it's not a problem. Why a static factory method, then ? – Joffrey Sep 10 '14 at 10:23
  • @Joffrey Using setArguments is only half of the battle. You also need to access the stuff using getArguments. – yydl Sep 10 '14 at 22:49
  • 3
    @yydl Well in any case, you have to use `getArguments`, because this is how the system works. The fact that you use a static factory method or an overloaded constructor to make your `setArguments` call does not affect the constraints you have to access the data. Using an overloaded constructor won't change anything here. – Joffrey Sep 11 '14 at 12:44
  • 1
    @yydl On the other hand, you could as well use setters to set some attributes of your fragment even when you use a static factory method. **It would be as bad as doing so from an overloaded constructor.** Using a sfm does not force programmers to call setArguments, you can do as much bad stuff as with a constructor. – Joffrey Sep 11 '14 at 12:46
  • 2
    @Joffrey True. I meant to say that by forcing this strange pattern, Android is highlighting that things are strange here. Essentially driving people to this question & answer. – yydl Sep 12 '14 at 03:15
  • @yydl That's right. Both approaches work, but I guess using the one recommended by Google is probably better, at least when your code is read by other programmers. – Joffrey Sep 12 '14 at 07:51
  • 2
    @Joffrey what I don't still don't understand is what the advantage of using a static method is. Why can't I just use the default constructor and then create and send the bundle directly from my code instead of calling a static method that does exactly the same thing? OTOH, using a static method for creating the fragment is a major problem when you need to create general code which is then overriden, since you can't overload a static method. If the whole idea is to force the "sender" to send the correct parameters you can define an object that contains the parameters that fragment needs. – theblitz Sep 14 '14 at 05:35
  • I am trying to do this for an abstract Fragment class, and I get an error that in the BaseListFragment myFragment = new BaseListFragment(); line -- saying that I cannot instantiate an object of an abstract class. What's the way out? – dowjones123 Jan 02 '15 at 22:56
  • 2
    @anticafe You can actually use `getArguments().getInt ` anywhere in the fragment... – yydl Apr 12 '15 at 03:12
  • where is fragment's onCreate() by the way? – Narendra Singh Mar 01 '16 at 09:38
  • When would one justify using android:configChanges="orientation|keyboardHidden|screenSize" ? – Luke Allison Mar 14 '16 at 01:52
  • 1
    With android studio, if you use the assisted fragment creation procedure (File>new>fragment) you will have a fragment with this approach already implemented – Apperside Jun 16 '16 at 12:22
  • Also you can use the Model View Presenter pattern, so the data in memory could be persisted anyway even if the fragment or activity is restarted. Here are a basic explanation about this. https://github.com/konmik/konmik.github.io/wiki/Introduction-to-Model-View-Presenter-on-Android – westrada Jul 08 '16 at 16:49
  • 1
    With this approach wouldn't you have to break down any object into a primitive? I want to pass a Date object to the fragment class, but there's no way to do that. Is the only solution breaking down the Date into day, month, and year ints? If so that seems insane that I have to destruct the object then reconstruct it inside the fragment. – Casey Hancock Jun 21 '17 at 02:35
  • 2
    @CaseyHancock See my comment above directed towards "@BenSewards" on July 30, 2013. Basically you can pass any object that can be placed into the bundle by using Parcelable (and Serializable). For a Date object, it looks like it only implements Serializable, but [see here](https://stackoverflow.com/questions/21017404/reading-and-writing-java-util-date-from-parcelable-class). – yydl Jun 21 '17 at 02:44
  • @6rchid What are you talking about? What is "this" and how does it "set" a method to null? You have to do the fragment transaction on the parent's ChildFragmentManager. Then getParentFragment() works from the child's onCreateView() on. – The incredible Jan Jan 19 '21 at 15:56
  • @Casey Hancock just use x = theDate.getTime() and later theDate = new Date(x). – The incredible Jan Jan 19 '21 at 15:59
  • Perhaps we should fight with recreating the fragment and use a normal constructor instead of using the Bundle crutch? This is a simpler and more understandable way for everyone. – Master Aug 10 '21 at 20:38
101

The only benefit in using the newInstance() that I see are the following:

  1. You will have a single place where all the arguments used by the fragment could be bundled up and you don't have to write the code below everytime you instantiate a fragment.

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    args.putString("someString", someString);
    // Put any other arguments
    myFragment.setArguments(args);
    
  2. Its a good way to tell other classes what arguments it expects to work faithfully(though you should be able to handle cases if no arguments are bundled in the fragment instance).

So, my take is that using a static newInstance() to instantiate a fragment is a good practice.

Sufian
  • 6,405
  • 16
  • 66
  • 120
500865
  • 6,920
  • 7
  • 44
  • 87
  • 7
    1) How is this any different than putting the logic in a constructor? Both are single places where you include this logic. 2) How are parameters on a static factory any different than parameters on a constructor? Both tell what arguments are expected. My point being it's a different paradigm, sure, but there's no clear benefit to this over using constructors. – RJ Cuthbertson Aug 11 '16 at 16:28
  • 4
    You cannot use custom constructors for fragment. Framework uses the no argument constructor for restoring fragments. – 500865 Aug 11 '16 at 18:53
  • 6
    Yes, I agree with you there. I'm saying conceptually there is no benefit in using the static factory pattern instead of using overloaded constructors, and vice versa. Both of your points are valid in both patterns; there is no benefit of using one over the other. Android forces you to use the static factory pattern - but there is no benefit to using one or the other. – RJ Cuthbertson Aug 11 '16 at 20:45
  • @RJCuthbertson A possible benefit would be the ability to create and return _subclasses_ of the static factory method's class i.e. to return an appropriate subclass for the situation. – urgentx Sep 02 '17 at 11:41
68

There is also another way:

Fragment.instantiate(context, MyFragment.class.getName(), myBundle)
Taryn
  • 242,637
  • 56
  • 362
  • 405
drlue
  • 1,143
  • 9
  • 8
  • If I am not mistaken, this is only possible when you use the Android Support library. – Timo Mar 25 '13 at 16:36
  • Its also possible without support library. – drlue Aug 07 '13 at 13:37
  • 2
    Tried this with the support library, but in onCreateView (in my fragment), the bundle passed was null, so I went with the setArguments/getArguments option and it worked (for anyone reading this). – Jonathan Apodaca Aug 28 '13 at 15:49
  • 1
    Interesting, I have not seen this approach before. Does it have any advantages over other approaches to instantiating a Fragment? – IgorGanapolsky Nov 12 '13 at 16:45
  • 25
    From the [developer docs](http://developer.android.com/reference/android/app/Fragment.html), `instantiate()` `Creates a new instance of a Fragment with the given class name. This is the same as calling its empty constructor.` – anon Feb 09 '14 at 16:13
  • 2
    Although they mentioned same as calling empty constructor. "args.setClassLoader(f.getClass().getClassLoader());" is called underneath for Bundle arguments – Gökhan Barış Aker Mar 17 '14 at 21:35
  • @IgorGanapolsky my guess would be that it is the method they use when fragment is in xml: `` – TWiStErRob Jul 28 '14 at 08:56
  • @IgorGanapolsky or it has the same use case as [Intent.setClassName](http://developer.android.com/reference/android/content/Intent.html#setClassName%28java.lang.String%2C%20java.lang.String%29), i.e. not having a class reference because it's in another (android) package? – TWiStErRob Jul 28 '14 at 08:56
  • 4
    `instantiate(...)` [methods](https://developer.android.com/reference/android/app/Fragment.html#instantiate(android.content.Context,%20java.lang.String)) are **deprecated** in API 28. Also, I don't think, it is good approach to create fragments. – Yekta Sarıoğlu Nov 16 '20 at 20:20
  • if it is deprecated, then what is the alternative solution then? @YektaSarıoğlu – gumuruh Mar 07 '22 at 02:30
  • @gumuruh newInstance()? – The incredible Jan Aug 24 '23 at 11:34
55

While @yydl gives a compelling reason on why the newInstance method is better:

If Android decides to recreate your Fragment later, it's going to call the no-argument constructor of your fragment. So overloading the constructor is not a solution.

it's still quite possible to use a constructor. To see why this is, first we need to see why the above workaround is used by Android.

Before a fragment can be used, an instance is needed. Android calls YourFragment() (the no arguments constructor) to construct an instance of the fragment. Here any overloaded constructor that you write will be ignored, as Android can't know which one to use.

In the lifetime of an Activity the fragment gets created as above and destroyed multiple times by Android. This means that if you put data in the fragment object itself, it will be lost once the fragment is destroyed.

To workaround, android asks that you store data using a Bundle (calling setArguments()), which can then be accessed from YourFragment. Argument bundles are protected by Android, and hence are guaranteed to be persistent.

One way to set this bundle is by using a static newInstance method:

public static YourFragment newInstance (int data) {
    YourFragment yf = new YourFragment()
    /* See this code gets executed immediately on your object construction */
    Bundle args = new Bundle();
    args.putInt("data", data);
    yf.setArguments(args);
    return yf;
}

However, a constructor:

public YourFragment(int data) {
    Bundle args = new Bundle();
    args.putInt("data", data);
    setArguments(args);
}

can do exactly the same thing as the newInstance method.

Naturally, this would fail, and is one of the reasons Android wants you to use the newInstance method:

public YourFragment(int data) {
    this.data = data; // Don't do this
}

As further explaination, here's Android's Fragment Class:

/**
 * 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.
 */
public void setArguments(Bundle args) {
    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mArguments = args;
}

Note that Android asks that the arguments be set only at construction, and guarantees that these will be retained.

EDIT: As pointed out in the comments by @JHH, if you are providing a custom constructor that requires some arguments, then Java won't provide your fragment with a no arg default constructor. So this would require you to define a no arg constructor, which is code that you could avoid with the newInstance factory method.

EDIT: Android doesn't allow using an overloaded constructor for fragments anymore. You must use the newInstance method.

Heath Borders
  • 30,998
  • 16
  • 147
  • 256
xyz
  • 3,349
  • 1
  • 23
  • 29
  • When would one justify using android:configChanges="orientation|keyboardHidden|screenSize" ? – Luke Allison Mar 14 '16 at 01:51
  • 1
    Android Studio now throws an error for all non-default constructors in fragments, so this no longer works. – Sheharyar Apr 30 '16 at 04:38
  • 6
    Holy man, I wonder how many droid developers have ever written code outside of droid. This is insane that we cannot use the approach you describe. There are NO compelling arguments from any comment as to why we HAVE to use static factory method. It's even more disturbing that they would raise an error when compiling. This is definitely the best answer provided and shows that there is no benefit to sfm. – MPavlak Aug 11 '16 at 14:58
  • 3
    Well, there is one subtle reason. You are free to create your own constructor with arguments, but there still *needs to be a no-arg constructor as well*. Since classes always have an implicit no-arg constructor *unless a constructor with args is explicitly defined*, this means that you would have to define both your arg-constructor *and* a no-arg constructor explicitly, or the system would not be able to invoke any no-arg constructor. I believe this is why the recommendation is to instead use a static factory method - it simply reduces the risk of forgetting to define a no-arg constructor. – JHH Oct 28 '16 at 08:18
  • @JHH that will fail at compile time itself, so not that big of a risk. However, the issue here is that constructor overloading, a key programming paradigm, is being denied by Android. – xyz Nov 02 '16 at 13:21
  • It will not fail at compile time. Android lint will complain about the lack of a default constructor but it will not prevent a debug build. In the event of a recreated fragment it will cause a runtime exception. – JHH Nov 02 '16 at 13:27
  • @JHH I don't know the details of how Android constructs the fragments. I meant to emphasise that since it would still result in a runtime exception, it can easily be corrected. However, if you store data outside of the argument bundle, it would be a hard bug to track down. But yes, the requirement of a default constructor is a pretty good reason as well. – xyz Nov 02 '16 at 13:37
  • The fact that fragments are only recreated in somewhat rare cases such as in a low memory situation or due to a configuration change makes it quite easy to forget adding a default constructor. That's why they added the lint warning I guess. Normally you create the fragment yourself with arguments, possibly not using the default constructor, and the default constructor is only used by the system in exceptional cases. If you use the static factory method, you are essentially using the same code as the system will, I.e., no-arg constructor followed by setArguments. – JHH Nov 02 '16 at 13:57
35

Some kotlin code:

companion object {
    fun newInstance(first: String, second: String) : SampleFragment {
        return SampleFragment().apply {
            arguments = Bundle().apply {
                putString("firstString", first)
                putString("secondString", second)
            }
        }
    }
}

And you can get arguments with this:

val first: String by lazy { arguments?.getString("firstString") ?: "default"}
val second: String by lazy { arguments?.getString("secondString") ?: "default"}
Jemshit
  • 9,501
  • 5
  • 69
  • 106
Rafols
  • 1,299
  • 14
  • 12
  • Is it best practice to use the `@JvmStatic` annotation? `@JvmStatic fun newInstance(bundle: Bundle) = SomeFragment().apply { arguments = bundle }` – AdamHurwitz Jul 19 '20 at 19:30
21

I disagree with yydi answer saying:

If Android decides to recreate your Fragment later, it's going to call the no-argument constructor of your fragment. So overloading the constructor is not a solution.

I think it is a solution and a good one, this is exactly the reason it been developed by Java core language.

Its true that Android system can destroy and recreate your Fragment. So you can do this:

public MyFragment() {
//  An empty constructor for Android System to use, otherwise exception may occur.
}

public MyFragment(int someInt) {
    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    setArguments(args);
}

It will allow you to pull someInt from getArguments() latter on, even if the Fragment been recreated by the system. This is more elegant solution than static constructor.

For my opinion static constructors are useless and should not be used. Also they will limit you if in the future you would like to extend this Fragment and add more functionality to the constructor. With static constructor you can't do this.

Update:

Android added inspection that flag all non-default constructors with an error.
I recommend to disable it, for the reasons mentioned above.

Ziem
  • 6,579
  • 8
  • 53
  • 86
Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
  • 5
    Another benefit of having a static method, which I did not mention above is that you cannot accidentally set properties from it. – yydl Sep 23 '14 at 22:10
  • 5
    Additionally, with regards to your point about "extend this fragment", this method would actually be really bad if you ever extend the class. Calling super will cause the setArguments() call to only be effective for either the child or parent, but not both! – yydl Sep 23 '14 at 22:13
  • Well it would depend on when you call super(...) in the child's implementation, but basically the point is the setArguments() only works for the last bundle that's set. – yydl Sep 28 '14 at 01:07
  • 2
    @yydle you can avoid this situation by calling get arguments to initialize the child Bundle. Java way always better. – Ilya Gazman Sep 28 '14 at 12:23
  • 10
    True, but that's another reason to encourage people to use the pattern Google has suggested. Of course, we all agree that your solution is 100% technically feasible. Much the same way there are many ways to do lots of things. The question, though, is whether it's the best. And I strongly feel that using the constructor does not represent the true nature of how this is supposed to work. – yydl Sep 29 '14 at 01:05
  • 4
    I agree with @yydl that static creation is better. One other benefit is dependency injection of future new dependencies - constructor is ill fitted for that and will likely cause more code change (or more constructors to be added). – Boon Sep 28 '15 at 18:12
  • 1
    Android Studio now throws an error for all non-default constructors in fragments, so this no longer works. – Sheharyar Apr 30 '16 at 04:38
  • @Sheharyar I added it to the answer, I recommend you to disable this inspection. – Ilya Gazman Dec 05 '16 at 17:03
  • When the Fragment is recreated, the non-default constructor is called, right? So how does this help? You quoted it yourself **So overloading the constructor is not a solution** – OneCricketeer Feb 14 '17 at 22:27
  • 1
    @cricket_007 I quoted it because I disagree with it, and here I offer the native Java approach to this issue – Ilya Gazman Feb 14 '17 at 22:53
  • I think I understand that, but `public MyFragment(int someInt)` won't be called by the OS, so... yeah – OneCricketeer Feb 14 '17 at 22:54
  • 1
    @cricket_007 It sound like you don't understand the setArguments method. When you call it is saves the data locally, so when the system will recreate the fragment from default contractor you will have the arguments as you set them in the non default constructor. – Ilya Gazman Feb 14 '17 at 22:57
  • 1
    No, I understand that piece. I think I see what you are getting at now -- You can supplement the default constructor with an overloaded one and the static one is useless. – OneCricketeer Feb 14 '17 at 23:05
  • @cricket_007 yep, this is it – Ilya Gazman Feb 14 '17 at 23:06
  • Some people simply forget to implement the no-arg one, though so that is why the static solution exists. Both are "native Java approaches" – OneCricketeer Feb 14 '17 at 23:10
  • 1
    Static solution supose to be a construcor but you can't override it. So its anty-oop aproach – Ilya Gazman Feb 14 '17 at 23:14
  • Of course, yydl is right. And doing static construtor `newInstance` is a common practice. When configuration change, a fragment will be created with a default constructor. – CoolMind Jun 19 '20 at 11:32
  • @CoolMind Didn't you read or didn't you understand the answer of Ilya Gazman? His solution just sets the bundle values from a normal constructor instead of a "static constructor". The result is the same. – The incredible Jan Aug 24 '23 at 11:53
  • @TheincredibleJan, of course, yydl is right, I can confirm it again. Also see their answers rates: +1256-1 against +25-4. So, why Ilya Gazman argues with evident? See also other opinions. See the answer of xyz, he writes better. – CoolMind Aug 24 '23 at 15:25
5

I'm lately here. But somethings I just known that might help you a bit.

If you are using Java, there is nothing much to change. But for Kotlin developers, here is some following snippet I think that can make you a basement to run on:

  • Parent fragment:
inline fun <reified T : SampleFragment> newInstance(text: String): T {
    return T::class.java.newInstance().apply {
        arguments = Bundle().also { it.putString("key_text_arg", text) }
    }
}
  • Normal call
val f: SampleFragment = SampleFragment.newInstance("ABC")
// or val f = SampleFragment.newInstance<SampleFragment>("ABC")
  • You can extend the parent init operation in child fragment class by:
fun newInstance(): ChildSampleFragment {
    val child = UserProfileFragment.newInstance<ChildSampleFragment>("XYZ")
    // Do anything with the current initialized args bundle here
    // with child.arguments = ....
    return child
}

Happy coding.

Zain
  • 37,492
  • 7
  • 60
  • 84
vhfree
  • 51
  • 2
  • 2
3

Best practice to instance fragments with arguments in android is to have static factory method in your fragment.

public static MyFragment newInstance(String name, int age) {
    Bundle bundle = new Bundle();
    bundle.putString("name", name);
    bundle.putInt("age", age);

    MyFragment fragment = new MyFragment();
    fragment.setArguments(bundle);

    return fragment;
}

You should avoid setting your fields with the instance of a fragment. Because whenever android system recreate your fragment, if it feels that the system needs more memory, than it will recreate your fragment by using constructor with no arguments.

You can find more info about best practice to instantiate fragments with arguments here.

Gunhan
  • 6,807
  • 3
  • 43
  • 37
  • The point isn't the static factory method. The point is the bundle. As long as you don't forget to implement the constructor without arguments it's the same as setting it by arguments of an own constructor. – The incredible Jan Aug 24 '23 at 11:56
2

Since the questions about best practice, I would add, that very often good idea to use hybrid approach for creating fragment when working with some REST web services

We can't pass complex objects, for example some User model, for case of displaying user fragment

But what we can do, is to check in onCreate that user!=null and if not - then bring him from data layer, otherwise - use existing.

This way we gain both ability to recreate by userId in case of fragment recreation by Android and snappiness for user actions, as well as ability to create fragments by holding to object itself or only it's id

Something likes this:

public class UserFragment extends Fragment {
    public final static String USER_ID="user_id";
    private User user;
    private long userId;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        userId = getArguments().getLong(USER_ID);
        if(user==null){
            //
            // Recreating here user from user id(i.e requesting from your data model,
            // which could be services, direct request to rest, or data layer sitting
            // on application model
            //
             user = bringUser();
        }
    }

    public static UserFragment newInstance(User user, long user_id){
        UserFragment userFragment = new UserFragment();
        Bundle args = new Bundle();
        args.putLong(USER_ID,user_id);
        if(user!=null){
            userFragment.user=user;
        }
        userFragment.setArguments(args);
        return userFragment;

    }

    public static UserFragment newInstance(long user_id){
        return newInstance(null,user_id);
    }

    public static UserFragment newInstance(User user){
        return newInstance(user,user.id);
    }
}
Tigra
  • 2,611
  • 20
  • 22
  • 3
    You said: "We can't pass complex objects, for example some User model, " - **It is not true, we can.** Like this: `User user = /*...*/` put the user to the bundle: `Bundle bundle = new Bundle(); bundle.putParcelable("some_user", user);` and get the user from arguments: `User user = getArguments().getParcelable("some_user");` The object must be implement Parcelable interface. [link](http://developer.android.com/reference/android/os/Parcelable.html) – Adam Varhegyi Sep 19 '15 at 13:30
  • 3
    Well, yes, but when class is complex and contains referrers to another objects... I personally prefer to keep it simple, either I have object, or I don't and then need to get it – Tigra Sep 19 '15 at 21:17
1
  1. Ideally we shouldn't pass anything in the fragment constructor, fragment constructor should be empty or default.
  2. Now the second question is, what if we want to pass interface variable or parameters-
    1. We should use Bundle to pass data.
    2. For Interface we can putParceble in bundle and make that interface implement parceble
    3. If possible we can implement that interface in activity and in fragment we can initialize listener in OnAttach where we have context[ (context) Listener].

So that during configuration change (e.g. Font change) the Activity recreation listener won't go uninitialize and we can avoid a null pointer exception.

Kelvin Schoofs
  • 8,323
  • 1
  • 12
  • 31
Vikram
  • 11
  • 1
0

Best way to instantiate the fragment is use default Fragment.instantiate method or create factory method to instantiate the the fragment
Caution: always create one empty constructor in fragment other while restoring fragment memory will throw run-time exception.

Mahesh
  • 2,862
  • 2
  • 31
  • 41
0

use this code 100% fix your problem

enter this code in firstFragment

public static yourNameParentFragment newInstance() {

    Bundle args = new Bundle();
    args.putBoolean("yourKey",yourValue);
    YourFragment fragment = new YourFragment();
    fragment.setArguments(args);
    return fragment;
}

this sample send boolean data

and in SecendFragment

yourNameParentFragment name =yourNameParentFragment.newInstance();
   Bundle bundle;
   bundle=sellDiamondFragments2.getArguments();
  boolean a= bundle.getBoolean("yourKey");

must value in first fragment is static

happy code

Amin Emadi
  • 17
  • 3
0

You can use smth like this:

val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, YourFragment::class.java.name)

because this answer now is Deprecated

Morozov
  • 4,968
  • 6
  • 39
  • 70
0

Create an instance of the fragment using kotlin code.

Write in activity

val fragment = YourFragment.newInstance(str = "Hello",list = yourList)

Write in fragment

fun newInstance(str: String, list: ArrayList<String>): Fragment {
        val fragment = YourFragment()
        fragment.arguments = Bundle().apply {
            putSerializable("KEY_STR", str)
            putSerializable("KEY_LIST", list)
        }
        return fragment
    }

Using the same fragment retrieve the data from bundle

val str = arguments?.getString("KEY_STR") as? String
val list = arguments?.getSerializable("KEY_LIST") as? ArrayList<String>
-2

setArguments() is useless. It only brings a mess.

public class MyFragment extends Fragment {

    public String mTitle;
    public String mInitialTitle;

    public static MyFragment newInstance(String param1) {
        MyFragment f = new MyFragment();
        f.mInitialTitle = param1;
        f.mTitle = param1;
        return f;
    }

    @Override
    public void onSaveInstanceState(Bundle state) {
        state.putString("mInitialTitle", mInitialTitle);
        state.putString("mTitle", mTitle);
        super.onSaveInstanceState(state);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
        if (state != null) {
            mInitialTitle = state.getString("mInitialTitle");
            mTitle = state.getString("mTitle");
        } 
        ...
    }
}
Vadim Star
  • 57
  • 1
  • 5
  • Except you have just been forced to override one more method and make a field that could have been isolated to the `onViewCreated` scope. It's convenience I guess, many ways to do the same thing. Also it's an easy way to check for updates done by the user (compare the bundles of `getArguments` and the bundle from `onSaveInstanceState`) – Overclover Dec 12 '16 at 13:43
  • @Asagen, I like your comment about compare initial and user values. I edited code and consider that it is still uniform and clear witout `getArguments` stuff. What about `onViewCreated` scope... We can restore state bundle there. But I just prefer make `onCreateView` light and fast and do all heavy initialization inside a `onActivityCreated` because `Fragment.getActivity()` sometimes like to return `null` and because of `onAttach()` changes in new version of API 23. – Vadim Star Dec 27 '16 at 17:57
  • All you did here was **move** `set` and `get` `Arguments` into `saveInstanceState`. You're essentially doing the same thing that is done "under the hood" – OneCricketeer Feb 14 '17 at 22:26
  • 1
    @cricket_007, or just **opposite**. Using `saveInstanceState` is "under the hood". And using of `Arguments` is duplication of functionality that make you double check: first `Arguments` values and then `saveInstanceState` values. Because you have to use `saveInstanceState` any way. What about `Arguments`... they are not necessary. – Vadim Star Mar 10 '17 at 16:38
  • Arguments are the equivalent of __Intent extras__ for fragments. They are not useless, they contain the initial parameters which is different from the current state. – BladeCoder Jul 14 '17 at 14:03
-10

I believe I have a much simpeler solution for this.

public class MyFragment extends Fragment{

   private String mTitle;
   private List<MyObject> mObjects;

   public static MyFragment newInstance(String title, List<MyObject> objects)
   MyFragment myFrag = new MyFragment();
   myFrag.mTitle = title;
   myFrag.mObjects = objects;
   return myFrag;
   }
  • 13
    mObjects will be cleared if MyFragment happens to be recreated (the user goes to the device home screen and later opens up the app which left off at MyFragment). You can retain mObjects by sending MyFragment a bundle as arguments. – ynnadkrap Jan 22 '15 at 22:18
  • 1
    Also, how is the static method accessing non-static member variables? – OrhanC1 Apr 28 '15 at 21:56
  • 2
    @ynnadkrap You are correct, using a bundle is the way to go here. – Stefan Bogaard May 04 '15 at 22:10
  • 2
    @OrhanC1 According to this example code, static method is not accessing to the member variables. The instance of MyFragment is accessing to its members. There is no error here. However, I do not recommend this answer to anyone because when your fragment is removed from the memory to open up some space by the android os then after restarting the activity and this fragment will be created with default empty constructor without assigning ant variables. – Gunhan Oct 28 '15 at 20:26