FragmentFactory and Dependency Injection Revolution in Android Apps

Not long ago I wrote an article about dependency injection in modularized Android applications. If you read that article, you might remember that towards the end I said that Google works on special factory for Fragments which will open some new exciting possibilities in the context of multi-module dependency injection. Several months later, FragmentFactory landed as part of AndroidX Fragments infrastructure.

In this post I’ll review the usage of FragmentFactory and then show you how it revolutionizes dependency injection in multi-module Android projects.

FragmentFactory

FragmentFactory API was introduced in AndroidX 1.1.0-alpha01. As far as I can tell, this addition was motivated by a need to support FragmentScenario class which is part of the new set of tools for integration testing on Android. I’m not a big fan of integration testing, but as you’ll see in a moment the value of FragmentFactory pertains beyond just testing.

So, what does it do?

Well, until now we had to use Fragments with default no-args constructors exclusively. This restriction was motivated by the fact that Fragments are re-created on config changes and save&restore by the system, but the system wouldn’t know how to satisfy their constructor dependencies. Therefore, when re-creating the Fragments the system always used no-args constructor and we had to do the same to avoid inconsistencies and partially initialized Fragments after re-creation.

FragmentFactory removes the above restriction by allowing you to “help” the system handle Fragments with non-default constructors. Once the system can handle non-default constructors, you can start using them too.

FragmentFactory Basic Tutorial

Let’s say you’ve got just one single Fragment in your app that you want to instantiate using FragmentFactory. The first step is to extend that class with your own implementation:

As you can see, FragmentFactory instantiates MyFragment and satisfies its two dependencies. If this factory will be asked to instantiate any other class of Fragment, it will simply delegate this responsibility to its superclass (which implements the “legacy” approach). This way you can migrate your Fragments to this approach one-by-one.

To force the system to actually use this factory, you need to set it as a default factory on a specific FragmentManager. For example, you can do the following in Activity’s onCreate():

This setting applies to all “child” FragmentManagers transitively. Therefore, if you do that in your Activities you don’t need to repeat the process in your Fragments.

Note that it’s crucially important that you set FragmentFactory before the call to super.onCreate(). This is required because the call to super.onCreate() will lead to re-construction of Fragments, so if the factory won’t be set you’ll get crash after config change or save&restore.

Lastly, when you want to switch Fragments manually, you can use your FragmentFactory in the following way:

While it didn’t become more complex, it also didn’t become much simpler. Taking into account the need to implement and use the custom FragmentFactory, the net result is probably increased complexity, which is not good. So, why would I want to use this approach then?

Well, the first use case is integration testing using FragmentScenario. As I already said, after some extensive experience with Robolectric in the past, nowadays I’m not a big fan of integration testing in Android. For the sake of discussion, let’s assume that you don’t do that either. Are there any other use cases?

In a single module application I’m not aware of any additional benefits of this new approach. However, it’s not the case in modularized Android apps.

FragmentFactory in Modularized Application

In my previous post about dependency injection in modularized Android apps I tried to convince you that the best modularization strategy is to have pure Java library modules. The second-best strategy is to have Android library modules, but without presentation layer logic in them (i.e. no Activities and Fragments in library modules).

However, sometimes, you need to put presentation layer logic into modules. It might be required due to organizational structure, or, maybe, you have complex screens shared among multiple applications, or any other special reason. How can you inject dependencies into Activities and Fragments in library modules then?

Well, in the previous post I listed several alternatives that you can use. However, all of them are hacky, with dagger.android being the culmination of excessively complex hacks. You can’t do proper dependency injection in this case because Activities and Fragments don’t support constructor injection.

Now the situation changed. At least for Fragments.

With the help of FragmentFactory, you can have Fragments in library modules and use proper constructor injection to provide their dependencies. No need for hacks anymore. No need for dagger.android.

To test how it all works in real application, I refactored my own pet project that uses Dagger to AndroidX Fragments and then modularized it.

Similarly to injection of ViewModels with ViewModelFactory, explicit Providers could be replaced with multibindings in this implementation. I don’t like multibindings due to their complexity and try to avoid this convention as much as possible, so I stayed with plain Providers.

As for adding the Fragments to the objects graph, you’ve got two options:

Evidently, the second option is simpler. However, I’m not sure how it affects incremental compilation and incremental annotation processing. Therefore, it might be the case that the second option incurs build-time penalties. I don’t have time to benchmark this hypothesis at this point, but I’ll be very glad to get readers’ input on this subject.

Summary

In this post I shared with you my excitement about the new FragmentFactory API. Its introduction is a true revolution in Android framework that opens new options for modularization of Android projects. With the help of FragmentFactory, you can finally have library modules that contain presentation layer logic and integrate easily into the complete application.

If you’ve been using dagger.android just because you wanted to use dependency injection in library modules that contained screens, you should definitely look into FragmentFactory.

One big question with respect to modularized dependency injection using FragmentFactory is what will be the impact of using @Inject annotation in library modules. Currently I recommend not using it and instantiating the Fragments from library modules manually. It doesn’t take that much effort and the gains in build times might be significant. Hopefully we’ll get more information from more informed community members soon.

As usual, you can leave your comments and questions below, and don’t forget to subscribe if you liked this post.

Subscribe for new posts!

5 Comments

One thing to consider when migrating to fragment factory, is that the fragment scope in Dagger will be the activity scope now. So we cannot provide in the DI graph objects obtained from fragments, like fragment’s layoutinflater. For this we need to use factories and pass them at runtime.

Hello Guilherme, I’m not sure I understand what you mean. Can you elaborate a bit? For example, I didn’t do any restructuring of my DI approach following refactoring to FragmentFactory, so I wonder if I missed some important aspect. Thanks

After following your courses (which are great BTW!), I restructured my app to use a PresentationModule; but I was passing a Fragment in the constructor, and not an Activity. Now I don’t remember exactly why I did this (maybe it was just an overlook on my side), but now by using the FragmentFactory I only have access to the Activity in the dependency graph in the PresentationComponent.

Maybe I did this to get the layout inflater directly from the Fragment, but I don’t know if there is any difference on getting one via the Activity.

I see. The only case where I’d consider having Fragment specific bootstrapping dependencies in PresentationComponent (I also call it ControllerComponent) is if I’d use nested Fragments. In this situation, I would probably need childFragmentManager on the objects graph. That said, I’ve been burned with nested Fragments years ago and I would hesitate to use them even today. Maybe that was your use case?

Guilherme February 7, 2019 at 10:11 pm

Actually no, in that particular project I have also tried to avoid nested fragments. Anyway, I have already changed the PresentationComponent to use activities. Thanks Vasiliy!