0

I have the following constructor inside a fragment:-

public PlaceDialogFragment(Place place, DisplayMetrics dm){
        super();
        this.mPlace = place;
        this.mMetrics = dm;
    }

I have also tried this:-

public static final DialogFragment newInstance(Place place, DisplayMetrics dm)
{
    DialogFragment fragment = new DialogFragment();
    Bundle bundle = new Bundle(2);
    bundle.putParcelable("Place", place);
    bundle.putLong("Metrics", dm);
    fragment.setArguments(bundle);
    return fragment ;
}

But There is an error on bundle.putLong("Metrics", dm) line

Here Place is a class which implements the Parceable interface

But i get an error saying:-

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

Any suggestions how to resolve this?

user3146095
  • 419
  • 2
  • 7
  • 25

6 Answers6

5

The reason you should use default constructors and pass arguments as bundles is because when the system restores your fragment state, it's gonna call the default constructor and restore the bundle. If you get your parameters from the bundle, then you can restore the state correctly.

Using your current method, everything you do in your custom constructor will be lost when the fragment is recreated.

See this answer for an example.

Community
  • 1
  • 1
Anup Cowkur
  • 20,443
  • 6
  • 51
  • 84
2

Use setArguments instead, while transacting the fragment, pass the constructor params in bundle, then use them in fragment using getArguments()

How to use setArguments() and getArguments() methods in Fragments?

What's the point of setArguments?

http://developer.android.com/reference/android/app/Fragment.html

You added :

    bundle.putLong("Metrics", dm);

Do like this:

bundle.putFloat("Metrics_density", dm.density);

Refer to DisplatMetrics documentation and add arguments separately, or add DisplayMetrics object as static in your Application memory, and use it from anywhere.

DisplayMetrics is not a Long object, not even parcelable, add relevant DisplayMetrics fields in bundle instead.

public static final PlaceDialogFragment newInstance(Place place, DisplayMetrics dm)
{
    PlaceDialogFragment fragment = new DialogFragment();
    Bundle bundle = new Bundle(2);
    bundle.putParcelable("Place", place);
    bundle.putFloat("Metrics_density", dm.density);
    //bundle.putFloat("Metrics_other", dm.<other fields>);
    fragment.setArguments(bundle);
    return fragment ;
}

Note : Don't use public constructor with parameters.

Community
  • 1
  • 1
himanshurb
  • 1,115
  • 1
  • 12
  • 22
  • I cant really figure out how to do it.. Could you please give me an example related to my code – user3146095 Jan 08 '14 at 08:46
  • I have edited, your code is mostly correct, just pass object types properly. – himanshurb Jan 08 '14 at 09:02
  • I used your code and that seems to have solved the problem. Now I need to access the constructor in other class like so :- PlaceDialogFragment dialogFragment = new PlaceDialogFragment(place,dm); how do i do it – user3146095 Jan 09 '14 at 06:51
  • I didn't get you, please edit your question with new query, and code samples. PlaceDialogFragment constructor should not have parameters. – himanshurb Jan 09 '14 at 07:40
1

Ideally, a fragment needs to reconstruct itself using only its arguments. A parameterised constructor does not work well for this as the parameters are lost in the case of a (for example) device orientation change (although you can mitigate this with a call to setRetainInstance).

Use a static method instead of a constructor to create your fragment.

e.g.

public static MyFragment newInstance() {
    MyFragment f = new FragStateList_();
    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    args.putString("someString", someString);
    f.setArguments(args);
    return f;
}

You should then include a default constructor so the system car re-create your fragment when it needs to.

In your updated question, you are attempting to place a DisplayMetrics objects into the bundle as a Long. The types are not compatible. Do not pass in the DisplayMetrics. Instead, try this in your fragment to get the DisplayMetrics object.

DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
Kuffs
  • 35,581
  • 10
  • 79
  • 92
1

The error message is right!

Avoid the use of Parameterized constructors to Fragment/Activity..

You can do "quick-fix" by going into Lint settings and excluding the rule + adding a default constructor. But quick fix is not the way. This will result in problem. Consider this case, you just rotate the screen, then your fragment gets destroyed and recreated when you call super.onCreate(savedState) of your activity, which will call default constructor => this results in NullPointerException.

So respect the Android Lint, make use of setArguments() to pass the instance of Place. If Place is your model class, make it Parcelable

you can get arguments by calling getArguments() inside your fragment

Thamme Gowda
  • 11,249
  • 5
  • 50
  • 57
1

Ideally, a fragment needs to reconstruct itself using only its arguments. A parameterised constructor does not work well for this as the parameters are lost in the case of a (for example) device orientation change (although you can mitigate this with a call to setRetainInstance).

-1

Like Kuffs wrote, the proper way to do this is to have a static method that calls a (default) constructor and after it is initialized, it adds your custom values. You can place arguments in that method, for example:

public static PlaceDialogFragment newInstance(Place place, DisplayMetrics dm) {
    PlaceDialogFragment f = new PlaceDialogFragment(); //alternatively new Fragment()
    f.mPlace = place;
    f.mMetrics = dm;
    return f;
}

Then from you Activity, you call it like:

PlaceDialogFragment pdf = PlaceDialogFragment.newInstance(param1, param2);
nstosic
  • 2,584
  • 1
  • 17
  • 21
  • I tried it and get an error like:- This method must return a result of type PlaceDialogFragment – user3146095 Jan 08 '14 at 08:54
  • I forgot to include `return f;` that was the error. Now it's ok – nstosic Jan 08 '14 at 08:56
  • 1
    This method is no better than using a parameterised constructor and should be avoided. There is no Bundle so the parameters will still be lost. – Kuffs Jan 08 '14 at 08:59