Best practice for instantiating a new Android Fragment
Asked Answered
H

17

783

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?

Hildebrand answered 12/2, 2012 at 0:42 Comment(2)
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.Feliks
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.Test
L
1260

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

Linnlinnaeus answered 12/2, 2012 at 0:57 Comment(32)
Then they should have make newInstance() for us to overrideEmeliaemelin
@Vlasto unfortunately static methods can't be overridden.Krefeld
@Linnlinnaeus 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)?Sue
Ah, I see that lint gives a warning if you a non-default constructor.Sue
This is also documented fairly well in the frag docs: developer.android.com/reference/android/app/…Tasteless
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;Enterprise
@Enterprise You must use a bundle if you want the data to be available when the fragment is later recreated.Linnlinnaeus
@Linnlinnaeus 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.Biocellate
@BenSewards Actually, the best way to do that would probably be to implement Parcelable and then putParcelable on the Bundle (you can also use Serializable, but it's not recommended)Linnlinnaeus
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.Norma
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. #11182680Broder
@Linnlinnaeus 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?Baptize
@Norma that's how a(ny) framework works, it give constraints on classes/objects it can work with. Activity.onCreate instead of a constructor is similar not to mention 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.Eddaeddana
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.Norma
@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 ?Tidings
@Tidings Using setArguments is only half of the battle. You also need to access the stuff using getArguments.Linnlinnaeus
@Linnlinnaeus 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.Tidings
@Linnlinnaeus 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.Tidings
@Tidings 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.Linnlinnaeus
@Linnlinnaeus 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.Tidings
@Tidings 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.Furriery
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?Jigging
@anticafe You can actually use getArguments().getInt anywhere in the fragment...Linnlinnaeus
where is fragment's onCreate() by the way?Denver
When would one justify using android:configChanges="orientation|keyboardHidden|screenSize" ?Karbala
With android studio, if you use the assisted fragment creation procedure (File>new>fragment) you will have a fragment with this approach already implementedCoral
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. github.com/konmik/konmik.github.io/wiki/…Abstemious
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.Satem
@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.Linnlinnaeus
@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.Labe
@Casey Hancock just use x = theDate.getTime() and later theDate = new Date(x).Labe
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.Shulock
B
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.

Bulimia answered 12/2, 2012 at 15:43 Comment(4)
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.Achromatous
You cannot use custom constructors for fragment. Framework uses the no argument constructor for restoring fragments.Bulimia
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.Achromatous
@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.Barbet
O
68

There is also another way:

Fragment.instantiate(context, MyFragment.class.getName(), myBundle)
Ovalle answered 9/3, 2013 at 14:26 Comment(11)
If I am not mistaken, this is only possible when you use the Android Support library.Extortionary
Its also possible without support library.Ovalle
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).Xenia
Interesting, I have not seen this approach before. Does it have any advantages over other approaches to instantiating a Fragment?Laskowski
From the developer docs, instantiate() Creates a new instance of a Fragment with the given class name. This is the same as calling its empty constructor.Pansir
Although they mentioned same as calling empty constructor. "args.setClassLoader(f.getClass().getClassLoader());" is called underneath for Bundle argumentsMeadowlark
@Laskowski my guess would be that it is the method they use when fragment is in xml: <fragment android:name="...">Eddaeddana
@Laskowski or it has the same use case as Intent.setClassName, i.e. not having a class reference because it's in another (android) package?Eddaeddana
instantiate(...) methods are deprecated in API 28. Also, I don't think, it is good approach to create fragments.Underpinning
if it is deprecated, then what is the alternative solution then? @YektaSarıoğluSternberg
@Sternberg newInstance()?Labe
W
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.

Warrior answered 16/6, 2015 at 12:39 Comment(8)
When would one justify using android:configChanges="orientation|keyboardHidden|screenSize" ?Karbala
Android Studio now throws an error for all non-default constructors in fragments, so this no longer works.Taryn
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.Froissart
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.Barclay
@Barclay 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.Warrior
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.Barclay
@Barclay 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.Warrior
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.Barclay
S
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"}
Shower answered 17/1, 2018 at 7:53 Comment(1)
Is it best practice to use the @JvmStatic annotation? @JvmStatic fun newInstance(bundle: Bundle) = SomeFragment().apply { arguments = bundle }Oleic
B
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.

Backwardation answered 23/9, 2014 at 12:14 Comment(19)
Another benefit of having a static method, which I did not mention above is that you cannot accidentally set properties from it.Linnlinnaeus
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!Linnlinnaeus
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.Linnlinnaeus
@yydle you can avoid this situation by calling get arguments to initialize the child Bundle. Java way always better.Backwardation
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.Linnlinnaeus
I agree with @Linnlinnaeus 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).Rosamariarosamond
Android Studio now throws an error for all non-default constructors in fragments, so this no longer works.Taryn
@Taryn I added it to the answer, I recommend you to disable this inspection.Backwardation
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 solutionFico
@cricket_007 I quoted it because I disagree with it, and here I offer the native Java approach to this issueBackwardation
I think I understand that, but public MyFragment(int someInt) won't be called by the OS, so... yeahFico
@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.Backwardation
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.Fico
@cricket_007 yep, this is itBackwardation
Some people simply forget to implement the no-arg one, though so that is why the static solution exists. Both are "native Java approaches"Fico
Static solution supose to be a construcor but you can't override it. So its anty-oop aproachBackwardation
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.Fino
@Fino 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.Labe
@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.Fino
M
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.

Mature answered 17/2, 2020 at 4:56 Comment(0)
H
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.

Horary answered 1/11, 2015 at 18:3 Comment(2)
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.Labe
Yes, the point is the bundle as in the answer. And better to have a static method to pass the arguments to prevent a case where you forgot to add the required fields.Horary
P
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);
    }
}
Predisposition answered 4/3, 2015 at 13:29 Comment(2)
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. linkAluminum
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 itPredisposition
A
2
  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.

Alderete answered 1/8, 2021 at 4:18 Comment(0)
T
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.

Threecornered answered 30/6, 2015 at 9:34 Comment(0)
G
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

Gimpel answered 9/11, 2019 at 13:55 Comment(0)
I
0

You can use smth like this:

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

because this answer now is Deprecated

Isomer answered 1/12, 2020 at 15:56 Comment(0)
C
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>
Cheeks answered 10/1, 2023 at 19:46 Comment(0)
A
0

Here is the way to create instances of any class including Fragments, if their constructors have the same arguments:

MyClass newInstanceOfClass (Class cls)
{
    try {
        return (MyClass) cls.getConstructor().newInstance();

    } catch (Exception e) {
        Log.e ("Error", "Error during creating a new fragnment instance of class " + cls + ": " + e);
        throw new RuntimeException(e);
    }
}

The same code with a single parameter:

MyClass newInstanceOfClassWithParam (Class cls, String param)
{
    try {
        return (MyClass) cls.getConstructor(String.class).newInstance(param);

    } catch (Exception e) {
        Log.e ("Error", "Error during creating a new fragnment instance of class " + cls + ": " + e);
        throw new RuntimeException(e);
    }
}

Usage:

instance = newInstanceOfClass (MyClass.class)

Don't forget to make your class public, otherwise it throws an exception.

Aldwon answered 9/2 at 10:56 Comment(0)
C
-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");
        } 
        ...
    }
}
Cadastre answered 6/12, 2016 at 14:33 Comment(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)Kinny
@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.Cadastre
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"Fico
@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.Cadastre
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.Bine
L
-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;
   }
Lamb answered 29/12, 2014 at 13:30 Comment(4)
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.Conveyancer
Also, how is the static method accessing non-static member variables?Envoy
@Conveyancer You are correct, using a bundle is the way to go here.Lamb
@Envoy 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.Horary

© 2022 - 2024 — McMap. All rights reserved.