Dagger2: @Component.Factory and @SubComponent.Factory

New way to bind instances to your component.

Roshaan Farrukh
AndroidPub
5 min readAug 28, 2019

--

Photo by Cassie Boca on Unsplash

While using dagger2 we all come across a situation where we want to pass dependency to our modules from outside in order to facilitate injection in other classes the most common example of this is passing application context to appmodule. There are other use cases too for example passing user id to User Detail Screen for which we need User Module to have User Id from outside.

Now that we understood the problem lets try to solve it. Previously there were 2 ways to solve this problem but Dagger 2.22 introduced another way. Lets analyze all three approaches to apply the best solution.

Approach 1: Modules with constructor arguments:

This approach simply says that pass constructor argument to the module.

Pass the context to the module simply while creating component.

Problem:

This looks quite straight forward but the problem with this approach is that we can’t make our module abstract(which is recommended as modules should not have states and modules methods should be statically available to dagger for better performance)and because of that we have to pass the instance of module to our component.

Approach 2: @Component.Builder:

In Dagger2.12 we got two new annotations @Component.Builder and @BindsInstances for doing the same thing we previously were doing by passing arguments to the constructor. We don’t have provide method in our module anymore.

As the name suggests @BindsInstances binds the instance to the component. By doing this we added the context to our dagger graph and now we can get context anywhere like before.

There are some rules that your builder interface should follow.

  • Builder must have at least one method which returns the Component or super type of the Component, in our example it is the build() function.
  • Methods other than build method that are used to bind instances should return the Builder type.
  • Methods used for binding dependencies must not have more than one parameter, if you want to bind more dependencies then create different methods for each dependency.

This is how our component will be created.

To understand how @Component.Builder works we have to look at the generated code. Our component interface name is AppComponent so dagger generated a class named DaggerAppComponent which is providing the implementation of our component. Dagger uses Builder pattern to create components, so inside our DaggerAppComponent class we have got static final class called Builder. Now because we have provided the builder interface in our AppComponent the inner Builder class present inside DaggerAppComponent implements that Builder interface created by us.

On calling build dagger passes the context passed by us to the component. Wooh!.

How this solution is better than the previous one?

Well we don’t have to pass constructor arguments any more so our modules can be stateless and can contain all static methods. Thats a success!

Problem

There is not as such of a performance related problem but if we want to bind many instances to the component then it will create a long chain and if we forgot to call any method in chain it will result in run time exception. So that’s the problem remaining to address.

That’s a long chain!

Approach 3: The winner @Component.Factory

With dagger 2.22 we have got yet another amazing annotation named @Component.Factory to address the problems that were introduced as the result of using @Component.Factory.

With Dagger 2.22 now we can use @BindsInstances with each parameter.

As precise as you like it, you can see how much lines of codes we have saved. Like @Component.Builder there are some rules that your Factory interface should adhere.

  • Your factory can not have more than 1 method. If you want to bind many dependencies then instead of creating method for each dependency(as we did with @Component.Builder) you can simply add a new parameter for each dependnecy.
  • Your method must return the type of Component or super type of Component.

And now our component will be created like this.

To understand how @Component.Factory works we have to look at the generated code. Inside DaggerAppComponent instead of Builder class now we get Factory class which is implementing our created Factory interface.

How this solution is better than the previous one?

  • Since we are not adding method for each dependency there will be no long chains and method count will remain same in every case.
  • Each dependency will add a parameter in a function and if we forgot to pass any dependency we will get a compile time error instead of run time exception

Like @Component.Builder and @Component.Factory there are also subcomponent version for both these annotations @SubComponent.Builder and @SubComponent.Factory.

There are still things remaining to cover regarding Factory annotation with subcomponents will write my next article on those.

--

--