FragmentFactory and Android Fragments

Chris Ribetti
Capital One Tech
Published in
4 min readNov 11, 2019
sunlight shining through the branches of tall trees with green leaves
Photo by Jenna Beekhuis on Unsplash

Fragments provide core Android app functionality. With the introduction of AndroidX in Android Jetpack, fragments got an overhaul and under the covers, the internals for fragment instantiation have changed.

Before AndroidX, the developer included a default, no-argument fragment constructor in their custom fragment class so the operating system could re-instantiate the fragment if necessary. AndroidX allows the developer to control the instantiation of fragments through a FragmentFactory object. With this, the developer’s custom fragment class can have a constructor with arguments.

Why use a custom FragmentFactory object? To control how fragments are instantiated. Why learn about FragmentFactory in the first place? It’s now the way things are being done internally. There’s the FragmentFactory class. There’s also the SingleActivityFactory class for testing. And there’s the AndroidViewModelFactory class inside of the ViewModelProvider class for providing ViewModels. Furthermore, code that includes factory classes and objects is becoming more common and a good understanding of how they work and are used is essential.

Let’s get to some code!

Fragments in Android

Android programming with fragments requires the developer to include an empty constructor in the event the operating system needs to reconstruct the fragment on its own. The OS will not use any constructors with arguments when re-instantiating, and so any arguments should be included by passing them in with setArguments(). You will need to define your fragment similar to the following:

Traditional custom fragment class

And then you supply your arguments when creating the fragment:

val fragment = MyFragment.newInstance("my argument")

The online reference documentation states that the developer should normally not implement a constructor, but rather use setArguments() so that the argument values will be automatically saved and restored (with getArguments()) alongside the fragment.

When the OS needs to reconstruct the fragment, it’s done in the instantiate() method in class Fragment:

android.app.Fragment.instantiate()

The code will only instantiate with newInstance(), the empty constructor. If the developer includes setArguments() in the initial fragment construction, the arguments will automatically be included during re-instantiation.

That was the way things worked. That is, until AndroidX.

Fragments in AndroidX

AndroidX are the Android libraries released by Google and are part of Android Jetpack, the suite of libraries and tools for Android development. AndroidX was announced at Google I/O in 2018 and the first stable release available later that year.

AndroidX includes an androidx.fragment.app package that includes an updated Fragment class in addition to a new FragmentFactory class. The Fragment class works just about the same as before and instantiate() is still there. But wait! The signature is now:

@Deprecated androidx.app.Fragment.instantiate()

Deprecated!? Yes. The Fragment class is deprecated since the new AndroidX paradigm is to use FragmentFactory instead. The idea is to have something else instantiate, something that will be under the developer’s control, and yet be available to the OS if necessary.

The new instantiate() documentation has information on the deprecation: “Use FragmentManager.getFragmentFactory() and FragmentFactory.instantiate(ClassLoader, String), manually calling setArguments(Bundle) on the returned Fragment.”

So, that’s what we’ll do. Except for the setArguments(). We’ll pass in arguments via a constructor.

Disclaimer: The reference documentation still says that you should generally not implement your own constructor and instead use setArguments() to pass arguments into the fragment. This is right after also stating to use a customFragmentFactory if you want to use a non-default (i.e. non-empty) constructor. Let the developer beware!

Creating and Starting a Fragment

Using a Custom FragmentFactory

Let’s take a look at the typical way to create and start a fragment in an activity, which should be a familiar implementation to all Android developers:

Activity without FragmentFactory

If, instead, we use a customFragmentFactory we will have:

Activity with FragmentFactory

Here, we instantiate a custom FragmentFactory and give it to the activity’s FragmentManager. This is optional, but allows us to set our custom factory once and be able to use it throughout the activity. Otherwise, a default factory will be used. Notice that setting the factory is done BEFORE super.onCreate(). This is necessary so that re-instantiation of fragments use the factory before the super.onCreate() lifecycle callback in AppCompatActivity re-instantiates them. Very important. Remember that. Set it BEFORE super.onCreate().

Instantiate the Fragment Using the Custom FragmentFactory

Then, like the documentation states, we tell the fragment manager to get its fragment factory, then instantiate the fragment from the factory. After that, the same transaction code executes.

So what does this instantiate() do? In FragmentFactory it looks like this:

androidx.fragment.app.FragmentFactory.instantiate()

It’s almost like the one for Fragment, but notably it doesn’t pass in arguments with setArguments(). The documentation tells us we need to do this ourselves and now we know why. It’s not here anymore!

Now, what does our custom FragmentFactory and instantiate look like?

custom FragmentFactory implementation

You may have many fragments. The class name passed in allows you to figure out which fragment to create. In this simple case we just create the fragment with our argument passed into a non-empty constructor. This custom FragmentFactory will allow the OS and the fragment manager to re-instantiate a fragment the way you want, rather than calling instantiate() in Fragment, which knows only to call the empty constructor.

Create the Signature for Our Fragment Class

With everything in place, we can write our fragment class signature like this:

class MyFragment(val arg: String) : Fragment() {

The non-empty constructor will be called. In a fragment. On OS re-instantiation. Every time. The OS is happy. YOU are happy. Let the developer beware.

Just one more thing…

I took a simplified approach above when creating aFragmentFactoryImpl implementation. To be more thorough, with dependency injection (for testing) or using the traditional fragment setArguments(), we can modify the above FragmentFactoryImpl to include a constructor argument and create the fragment with the no argument constructor and pass in the argument with setArguments():

another custom FragmentFactory implementation

Thank you for reading and implementing!

DISCLOSURE STATEMENT: © 2020 Capital One. Opinions are those of the individual author. Unless noted otherwise in this post, Capital One is not affiliated with, nor endorsed by, any of the companies mentioned. All trademarks and other intellectual property used or displayed are property of their respective owners.

--

--

Chris Ribetti
Capital One Tech

Developer at JPMorgan Chase. Everything Android, Math, Quantum, Physics, Cosmology, Maps and yes, Mainframe.