Best practice for instantiating a new Android Fragment

前端 未结 13 1473
暖寄归人
暖寄归人 2020-11-21 04:38

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

Fragment newFragment = new MyFragment();

and

<         


        
相关标签:
13条回答
  • 2020-11-21 05:08

    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.

    0 讨论(0)
  • 2020-11-21 05:09

    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;
       }
    
    0 讨论(0)
  • 2020-11-21 05:10

    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.

    0 讨论(0)
  • 2020-11-21 05:11

    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.

    0 讨论(0)
  • 2020-11-21 05:18

    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.

    0 讨论(0)
  • 2020-11-21 05:20

    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

    0 讨论(0)
提交回复
热议问题