Why use newInstance for DialogFragment instead of the constructor?

14,303

Solution 1

If you overload the constructor with MyAlertDialogFragment(int title), the Android system may still call the default MyAlertDialogFragment() constructor if the Fragment needs to be recreated and the parameter is then not passed.

Solution 2

If you create a DialogFragment that receives objects through the constructor, you will have problems when android recreates your fragment. This is what will happen:

  1. your code creates the dialog calling the constructor you have created and passing some arguments as dependencies.
  2. your dialog runs, and uses the dependencies that you passed though the constructor
  3. the user closes the app
  4. time passes, and android kills the fragment to free memory
  5. the user opens the app again
  6. android will recreate your dialog, this time using the default constructor. No arguments will be passed!
  7. Your dialog will be in a undesired state. It may try to use instance variables that you expected to pass through the constructor, but as they are not there you'll get a null pointer exception.

To avoid this, you need not to rely on the constructor to establish the dependencies, but in in Bundles (arguments and saved instances). That may force you to implement Parcelable in some classes, which sucks.

EDIT: you can reproduce Android killing the app (step 4) by enabling the "don't maintain Activities" in the Development settings. That's the way to easily test it.

Solution 3

Android relies on Fragments having a public, zero-argument constructor so that it can recreate it at various times (e.g. configuration changes, restoring the app state after being previously killed by Android, etc.).

If you do not have such a constructor (e.g. the one in the question), you will see this error when it tries to instantiate one:

Fragment$InstantiationException: Unable to instantiate fragment 
make sure class name exists, is public, and has an empty constructor that is public

Arguments given to it by Fragment.setArguments(Bundle) will be saved for you and given to any new instances that are (re)created. Using a static method to create the Fragment simply provides an easy way to setup the required arguments whilst maintaining a zero-argument constructor.

Solution 4

Because when android is recreating a fragment, it always uses the empty constructor, and by using newInstance() you can set data that fragment uses when recreating, for example when the screen is rotated

for example:

   public static FragmentExample newInstance(Parcelable uri) {
    FragmentExample fragmentExample = new FragmentExample();

    Bundle bundle = new Bundle();
    bundle.putParcelable("Uri", uri);
    fragmentExample.setArguments(bundle);

    return fragmentExample;
}
Share:
14,303

Related videos on Youtube

rfgamaral
Author by

rfgamaral

Updated on October 20, 2022

Comments

  • rfgamaral
    rfgamaral over 1 year

    Looking at the documentation of DialogFragment, one sees the static newInstance method to initialize a new alert dialog fragment. My question is, why not use a constructor to do so, like this:

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

    Isn't this exactly the same or does it differ somehow? What's the best approach and why?

  • rfgamaral
    rfgamaral over 11 years
    What if I add 2 constructors? Both public, one with zero arguments and the one with the arguments I want... Wouldn't that work too?
  • rfgamaral
    rfgamaral over 11 years
    I'm confused and not sure how exactly this answers my question... Care to clarify?
  • onosendai
    onosendai over 11 years
    You asked: "My question is, why not use a constructor to do so, like this: public MyAlertDialogFragment(int title)". My answer says that if you use this constructor it may not get called if the Fragment is re-created by the Android system, and the argument you wanted passed is not passed. So don't use this approach.
  • antonyt
    antonyt over 11 years
    Yes, I guess that would work too, you can use the multi-arg constructor when constructing it yourself, and then Android will use the zero-arg one when it is recreating it. Arguments will be saved properly if you used setArguments(..) in the multi-arg constructor. You really just have to keep clear in your mind what happens when the fragment is recreated - the static factory method style makes it more distinct for me, but that might be because I (and many others) am used doing it that way. Following the standard conventions will make your code easier to understand by others.
  • Glenn Maynard
    Glenn Maynard about 11 years
    This answer doesn't make sense. It's perfectly valid to have a constructor for this; you just have to provide another constructor with no arguments as well.
  • Glenn Maynard
    Glenn Maynard about 11 years
    There's no reason to have a static method; just have two constructors.
  • Justin
    Justin almost 11 years
    Glenn, did you even read the answer? Two constructors will not solve the problem
  • sshaw
    sshaw almost 11 years
    I assume that would cause problems for you if you rotate your device. Instead of calling your constructor it'll just call the default constructor. So, anything you intend to be setup through your overloaded constructor won't be executed.
  • xesxz
    xesxz almost 10 years
    This answer makes sense if you do not call setArguments(Bundle) in the constructor, which is not the case here.
  • xesxz
    xesxz almost 10 years
    Justin, did you read the question? In this case (where setArguments is called in the constructor), two constructors will certainly solve the problem.