No so long ago, in the androidx.fragment artifact, the Android team introduce the shining new FragmentFactory to let you take controller over the Fragment’s instantiate process, open a way for you to perform constructor injection on Fragment class.

In this article, I will walk you through problem and step by step solution in order to perform constructor injection on Fragment class while still maintain the correct scope.

TL;DR

Prerequisite

This article assumes that you are already familiar with dagger-android multi-binding scope subcomponent . If you are not sure what I’m talking about, I recommend checking out dagger’s documentation first.

The unexpected

If we perform constructor injection on Fragment means it cannot have dependencies that depend on the Fragment itself because that would create a circular dependency.

Why this is not a problem with member injection? Because the subcomponent (along with fragment scoped dependencies) is created after the Fragment itself so Fragment’s dependencies can have a reference to the Fragment. This is not the case with constructor injection because of all Fragment, Fragment’s Subcomponent, and Fragment’s dependencies are created at the same time.

Light at the tunnel’s end

What exactly those kinds of dependencies that need a reference to fragment? Turn out this is pretty common for example, FragmentNavigator (an object that handles all fragment navigation), FragmentArgs (require fragment to parse data from its bundle, typically used in ViewModel)

Turn out those dependencies didn’t use fragment reference immediately at creation time, instead, they only use when they needed. Example, the FragmentNavigation only use fragment reference when user performing navigation, this event happened way after the FragmentNavigator creation time.

For this particular reason, we could use a holder object and its job is to hold fragment reference. Dependencies that need fragment reference could depend on the holder instead.

Within fragment’s scope, we will provide a singleton Holder<Fragment> , at creation time fragment reference will be null . When create fragment we request that holder, create fragment then set fragment reference to holder. All of this logic is performed in the DI code.

Dirty hands

Moving on to the implementation part. While using the FragmentFactory to instantiate our Fragment, we still what the Fragment and all of its dependencies scoped, which mean we need to use Subcomponent and the Fragment instance much be pulled out from the Subcomponent .

In the FragmentFactory implementation, we can inject the corresponding FragmentComponentFactory and create the fragment from there

While our application likely to have many Fragment, this is where we can lever Dagger’s multi-binding to do the work for us.

For multi-binding, we need a common interface for ours FragmentComponent and FragmentComponent ’s Factory

Each binding also need a key, Fragment itself would be the appropriate one

Binding setup:

Cleaner FragmentFactory implementation:

Remember to register our FragmentFactory to the activity before super.onCreate() so that it can be used when re-creating fragments after rotation or process death

Bug or feature?

In order to make Dagger generate Fragment’s ComponentFactory, you have to declare it in your component, feel a bit odd because when other Components depend on our ApplicationComponent they will know about all the FragmentComponentFactory as well. This is the limitation of Dagger.

Caution

With the introduction of Holder<T> we introduce 2 runtime exceptions

Forget to set the Fragment reference to Holder Use Fragment reference before it was set

To eliminate those exception makes sure:

Set the Fragment reference to holder right after it is created, set it only once and in the Dagger code Making sure that types depend on Holder<Fragment> don’t use the reference immediately yHolder<Fragment> much be singleton (within the Fragment)

Final touches

Dynamic Features

Because of our FragmentFactory is unscoped, we can use this in any component just by declare the binding module.

Android Navigation Component

From 1.0.0-alpha08 the navigation component will use the Activity ’s FragmentFactory to create Fragment

Fragment creation has been moved to FragmentNavigator , making it easier to delegate Fragment creation to a FragmentFactory . b/119054429

Scoping Fragment?

You don’t need to scope Fragment with @FragmentScope because it only requested once (in the FragmentFactory )

Thank

You can check out the working example here, which include the FragmentFactory Dagger setup, Multi-binding and uses in dynamic features.

As always I will answer any question you have in the comment section. See you there!