Mickey Williamson

Android Fragments and Static Factory Methods

Typically when we create a class, we create one or more constructors for the class:

public MyClass {

    private int myInt;
    private String myString;

    public MyClass(int someInt) {}

    public MyClass(int someInt) {
        myInt = someInt;
    }

    public MyClass(String someStr, int someInt) {
        myInt = someInt;
        myString = myString;
    }
}

We then use the “new” operator to instantiate the class and pass in an argument:

MyClass myClass = new MyClass(5);
MyClass myClass = new MyClass("Take", 5);

This works in the more common scenarios but isn’t flexible enough in others. What if we needed to:

  • Return an subclass of the class instead of the class itself
  • Return a subclass of the class based on the parameters passed in
  • Return an already created instance of the class instead of a new instance (cache, singleton)
  • Have multiple constructors with the same signatures?

Enter Static Factory Methods.

[Note: Static Factory Methods are not connected with the Factory Method design pattern.]

Instead of using constructors to instantiate objects, we use public methods with names that describe what they do. Example method names include from, of, valueOf, instance, getInstance, create, and newInstance.

For instance, the valueOf method of the String class is one such static factory method. Instead of creating a string using the string’s constructor String myString = new String(5), valueOf is an overloaded method that takes several different kinds of parameters, converts them to a string and returns a string object:

String myString = String.valueOf(2);



Uses of Static Factory Methods in Android

Examples of the use of static factory methods in Android include:


LayoutInflater

Instead of using a constructor, the LayoutInflater is obtained from context using the from method:

LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.some_layout, root);)


NotificationManagerCompat

The NotificationManagerCompat class is also instantiated from context using the from method:

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(0, notificationBuilder.build());


Fragment

When extending the Fragment class, if data is to be passed into the Fragment, it is best practice to create a static newInstance method that receives the data and passes the data in a Bundle using setArguments so it can be retrieved from the Bundle with getArguments. This is because when the device is rotated or other configuration change is made, the fragment is destroyed and recreated. When the system recreates the fragment the default empty constructor is used (which is why the compiler complains if there is no empty constructor on a Fragment subclass). So if you create a second constructor that get arguments passed in, that constructor will never be called and the data will never get passed in. By passing and retrieving the data via the Bundle, it doesn’t get destroyed along with the fragment and is available to the fragment when it is recreated by the system.

public class MyFragment extends Fragment {

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

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

        return myFragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        getArguments().getInt("myInt", 5);
    }
}
MyFragment fragment = MyFragment.newInstance(5);


Summary

Hopefully that demystifies the use of the newInstance method for extending the Fragment class when passing in data. It is simply a static factory method used to instantiate a class rather than using a constructor.

For additional enlightening information on static factory methods, see Effective Java (Third Edition) by Joshua Block – Item 1.

Leave a Comment