Android Fragments: FragmentFactory
Fragment constructor injection is now -and has been for a while- supported in Android thanks to FragmentFactory. While it isn’t an API developers have to use, it can be regarded as a better design approach in certain situations and can help when testing Fragments with external dependencies.
This article explains what a FragmentFactory is, how and when to use it, and how it behaves with nested Fragments.
What is a FragmentFactory?
TL;DR A class used to control the instantiation of Fragment
instances.
Traditionally, a Fragment instance could only be instantiated using its default empty constructor. This is because the system would need to reinitialize it under certain circumstances like configuration changes and the app’s process recreation. If it weren’t for the default constructor restriction, the system wouldn’t know how to reinitialize the Fragment instance.
FragmentFactory was created to work around this limitation. It helps the system create a Fragment instance by providing it with the necessary arguments/dependencies needed to instantiate the Fragment.
How to use a FragmentFactory?
TL;DR By extending FragmentFactory
and overriding FragmentFactory#instantiate()
, then assigning it to a FragmentManager
.
If your Fragment has a non-empty constructor, you will need to create a FragmentFactory that will handle initializing it. This is done by extending FragmentFactory, and overriding its method FragmentFactory#instantiate()
.
Fragments are managed by FragmentManagers, so it’s only natural that the FragmentFactory needs to be attached to a FragmentManager in order to be used. More specifically, it must be assigned to the FragmentManager of the component that will contain the Fragment, this can be an Activity or another Fragment. More on this below.
When should a FragmentFactory be assigned to a FragmentManager?
TL;DR Before the parent Activity#onCreate()
and Fragment#onCreate()
are called.
The FragmentFactory responsible for initializing a Fragment inside a component -Activity or parent Fragment- should be set before the Fragment is ever created. This means:
- Before the component’s View is created, if the Fragment is defined in an XML layout using the fragment tag
<fragment>
or aFragmentContainerView
. - Before the component creates the Fragment, if the Fragment is dynamically added using a FragmentTransaction.
- Before the system restores the Fragment, if the Fragment is being recreated after a configuration change or the app’s process restart.
Given these restrictions, it’s safe to assign the FragmentFactory to the component’s FragmentManager before Activity#onCreate()
and Fragment#onCreate()
-which are the base classes of your Activity
and Fragment
- are called, as both these calls handle reinitializing previous Fragments, and run before creating the view.
In practice, this means that the FragmentFactory should be assigned before calling super#onCreate()
.
Do you need to use a FragmentFactory?
TL;DR No, but in certain situations a FragmentFactory
might be the better design option.
So far, you’ve probably been creating your Fragments using their default constructors, then either injecting the dependencies they require using a library like Dagger or Koin, or simply initializing them inside the Fragment at some point before they’re used.
If your Fragment has a default empty constructor, there’s no need to use a FragmentFactory. If however, your Fragment takes in arguments in its constructor, a FragmentFactory must be used, otherwise a Fragment.InstantiationException will be thrown, since the default FragmentFactory that will be used will not know how to instantiate an instance of your Fragment.
How to use a Fragment and a FragmentFactory hand in hand?
TL;DR Add the FragmentFactory as described above, then add the Fragment as you would usually do.
As mentioned above, as long as the FragmentFactory is set before the Fragment needs to be created, it will be used to instantiate it. This means that a custom FragmentFactory can be used when adding Fragments:
- Statically with the fragment tag
<fragment>
andFragmentContainerView
.
- Dynamically with the overloaded
FragmentTransaction#add()
methods that take as input the Fragment class or the Fragment instance.
FragmentFactory and nested Fragments
TL;DR Nested Fragments use their parent’s FragmentFactory, unless overridden.
If a parent Fragment contains nested Fragments or multiple levels of nested Fragments, then by default, they all use the same FragmentFactory from the parent Fragment. However, a nested Fragment can override this by calling Fragment#childFragmentManager.fragmentFactory
.
Conclusion
FragmentFactory now allows Fragment constructor injection, which wasn’t possible for a long time in Android. Furthermore, migrating to it can be done one Fragment at a time, making its adoption relatively easy.
For more on Fragments, check out the resources below.