Dagger 2 on Android: the shiny new @Component.Factory

Yet another way to bind instances

Fred Porciúncula
ProAndroidDev

--

Photo by Sam Bark on Unsplash

How do you add the application context into your object graph? There used to be two different ways to do that (or three, if you happen to like dagger-android), and now there's a new one that just came out with Dagger 2.22: the @Component.Factory.

We'll go through all of them so we can see where we're coming from and why we should appreciate and take advantage of this new feature, not only as a way to bind the application context, but as the proper way to bind any instances we don't control.

The lame module with constructor argument

Traditionally, that's how we'd setup our ApplicationComponent with the application context:

We create a module that receives the context as a constructor argument, and we expose it in a @Provides method. We can actually make the module look cuter thanks to Kotlin:

And this is how we build the component:

If you started working with Dagger a few years ago, this probably looks familiar to you. And we can actually use the same technique whenever we want to add objects constructed outside the graph into subcomponents. That's how we'd inject a view into a presenter, for instance:

We need this line in the ApplicationComponent to glue our subcomponent:

And then, assuming we can get our ApplicationComponent through the Application class somehow, this is how we can get the presenter in our activity:

However, besides the noticeable verbosity, we know by now that modules should be stateless and only have static provide methods, and it's clear that's not the case there.

The cool @BindsInstance

Starting with Dagger 2.9 a couple years ago, we're able to annotate methods within a component (or subcomponent) builder so we can easily bind instances constructed outside of the graph. It's not really less verbose than the previous solution, but it doesn't require a weird stateful module, so that's already a big win.

This is how the ApplicationComponent would look like:

And here's how we build it:

Again, we can use the same idea on subcomponents as well:

That's a pretty big chain right there… the nice thing here is that we don't need the module anymore. But it still feels things could be improved, right?

The @Component.Factory

The recent Dagger 2.22 introduced an alternative to the component (or subcomponent again) builder, which is the component factory. A factory here is basically a more versatile (and less verbose!) builder. Instead of annotating individual methods, the factory has only one single method and we can annotate its parameters.

This is how our ApplicationComponent looks like now:

And here's how we can create it:

This is definitely less verbose and it looks quite nice. And the most important point that I originally missed here is that this change brings compile time safety: before, if we had multiple builder methods, it’d be possible to forget to call one of them and it’d still compile. Now there’s always one single method, and whenever we call it we must provide every argument, so it’s not possible anymore to forget to provide a mandatory dependency to the component. Thanks @ph1b for pointing that out!

Once again, we can do the same in a subcomponent:

One thing to keep in mind is that even though this works pretty well, if we're not really taking advantage of the subcomponent there (by using a custom scope, for instance), it's probably better — as in significantly less verbose — to go with AssistedInject instead whenever we want to add objects that come from the activity (like an intent extra, or the activity itself, or a fragment, etc) into the graph.

That's not all for the @Component.Factory. We can also use it for component dependences and modules, for instance, but I wanted to illustrate the most obvious scenarios we can take advantage of it. Make sure to take a look at the docs to see how else you can work with it.

--

--