Dagger 2 Subcomponent Illustrated (Kotlin)

Elye
Elye
Nov 3 · 8 min read
Picture by Yan Ots on Unsplash

Dagger 2 reference documentation on Subcomponent is compact. It’s not easily digestible. So I made one version referring to its content, and add illustration and code in Kotlin. Hope that helps make it easier to consume.


In Dagger 2, component is the main container-like object that binds all the dependencies (or it’s factory).

Subcomponent are components that is like an extension to its parent component.

It can be used for

  1. Partition the dependencies into different compartments. Avoid the parent component to have too many dependencies bound to it.
  2. Subcomponent and its parent component have different scope (of lifespan). The subcomponent scope is smaller than its parent.

Subcomponent can access all its parent bound dependencies, but not vice versa. The relationship is illustrated further below.

Declaring a subcomponent

To create as subcomponent,

  1. Use @Subcomponent to annotate on an interface (or abstract class).
  2. Add your subcomponent modules by adding to the Module parameter.
  3. Create the Builder using @Subcomponent.Builder. (Optional, but preferred in some cases. Refer to this blog for comparison.

Adding a subcomponent to a parent component

Unlike coding inheritance, where the child define who the parent is, in Dagger 2, the parent define who the child (subcomponent) is.

In another word, the child could have multiple parents, as long each of the parent has all the child needed dependency

There are two approach

1. Through the parent component’s module

Add the subcomponent class to the subcomponents attribute of a @Module that the parent component installs.

Note: Even thought the Subcomponent is linked through the ServerModule, other module (if there is) within the ServerModule can also have access to the Subcomponent’s builder.

2. Through the parent component abstract function.

Create an abstract function (or in Kotlin, we could have interface property) that generate the Subcomponent’s Builder (or the subcomponent itself)

As of which to use or not, refer to this blog for comparison.


With either of the approach above, the parent bounded dependency can be injected with the child component Builder

Subcomponents and scope

In Dagger 2, Scope is used to help determined the lifespan of an object. An un-scope object is always created a new when being called. But a Scope object is created once per scope defined lifespan. Refer the below blog to understand more

For Subcomponent, it enables one to have smaller scope than what the parent component has. The default scope is @Singleton. If the parent component @Singleton, then its subcomponent need to have a smaller scope, which can only be constructed using custom scope.

Example custom scopes is written as below

In term of Scope, the rules as below

  • The parent component and child component (or anything between the ancestry line) cannot be of the same scope
  • Un-scope parent component can refer to a scope child component.
  • The sibling components could may be using the same scope annotation, but they scope lifespan is different (within the respective subcomponent build existence)

Another example, we have a RootComponent that is @Singleton scope, that has a child component called SessionComponent with @SessionScope. In SessionComponent, it has two child components, that is scoped with @RequestScope, named FooRequestComponent and BarRequestComponent, which is considered sibling to each others. This compiles find, as FooRequestComponent and BarRequestComponent doesn’t have direct ancestry line between them.

Subcomponents for encapsulation

The other benefit of Subcomponent is, it could be used to encapsulate its objects (in the Subcomponent).

Non-Encapsulation

Imagine if Database is dependent on DatabaseScheme and DatabaseConnectionPool, and all of them are provided by the within the same component, then DatabaseConnectionPool and DatabaseScheme could be easily accessible. This is not ideal.

Encapsulation

However, we can encapsulate those dependence into a Subcomponent (i.e. DatabaseComponent) as per the code below. This will hide away DatabaseScheme and DatabaseConnectionPool from being accessible by others other than Database itself.

Defining subcomponents with abstract factory methods

As mentioned in the Adding Subcomponent to Parent section above, we could have abstract factory methods (or interface property in Kotlin) that return the subcomponent

Module with parameter

Assuming if the Subcomponent’s module (i.e. RequestModule) need to have argument

Then we could add the parameter to the abstract function (can’t use Interface Property of Kotlin anymore in this case)

Sharing module with parent

Imagine if both the Parent and the Subcomponent having the same module. The Subcomponent will just take the parent’s component.

Return the Subcomponent’s builder instead

In the parent component, other than returning the subcomponent, we could return the builder instead as shown in example code below. This would make it possible to use the subcomponent’s builder provided parameter (e.g. Module creation, @BindsInstance data etc) .

Comparison consideration

Should we return the Builder or not? Should we consider using Abstract Factory Method or just use the subcomponent parameter in the Parent’s Module?

Below are two blogs for more reading any comparing the differences.

Details

Extending multibindings

Multibindings is a feature in Dagger2 that allow binding of instances into a Set or Map of Data that could be provided/injected into its target.

Subcomponent has enable Multibindings feature a different (or rather super) set/map of data in the subcomponent, than what the parent provides.

Illustrated in the diagram below, the parent provide only string1 and string2. For the same Set<String>, within the child’s scope (i.e. Subcomponent Scope), it provides string1, string2, string3 and string4. This enables each subcomponent to provides different set of Set<String>

,

For more about Multibindings, refers to the blog below.

Repeated Module in Subcomponent (Not supported Error)

If a required module by the subcomponent, already provided by the Parent, the subcomponent shouldn’t build its own subcomponent. It will either compile error or clash during run time depending on how the builder is called.

Below are 3 examples


Hope this provided a clearer understanding of what Subcomponent is and how it function.

The working code (in Kotlin) is available below

Thanks for reading. You could check out my other topics here.

Follow me on medium, Twitter, Facebook or Reddit for little tips and learning on mobile development etc related topics. ~Elye~

Elye

Written by

Elye

Learning and Sharing Android and iOS Development

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade