Dagger 2 Subcomponent: through module or component comparison

Elye
Elye
Oct 27 · 3 min read
Picture by Coffee Geek on Unsplash

Dagger 2 provides subcomponent feature. There are 2 ways we could create subcomponent. I’ll be comparing them side by side

The syntax of creation

1. Through the parent component

@Component
interface ParentComponent {
val childComponent: ChildComponent
}

Using this approach, we could also have access to the ChildComponent’s Builder

@Component
interface ParentComponent {
val childComponentBuilder: ChildComponent.Builder
}

Note: When to use the Builder or not refer to this blog.

2. Through the parent module

@Module(subcomponents = [ChildComponent::class])
class ParentModule
@Component(modules = [ParentModule::class])
interface ParentComponent

The comparison

1. Lazy creation of ChildComponent

  • Through the ParentComponent, the ChildComponent (or the Builder) will always be created regardless if it is used or not ❎
  • Through the ParentModule, the ChildComponent will only be created when it is needed (depend upon) ✅

2. Need of ChildComponent.Builder

  • Through the ParentComponent, we don’t need to have an explicit ChildComponent’s Builder (unless the ParentComponent request to have the ChildComponent’s Builder) ✅
  • Through the ParentModule, the ChildComponent need to explicitly have it’s Builder defined ❎
@Subcomponent(modules = [ChildModule::class])
interface ChildComponent {
@Subcomponent.Builder
interface Builder {
fun build(): ChildComponent
}

}

3. Semantically correctness

  • Through the ParentComponent, it is more semantically correct, as all the Parent’s Module would be able to access the Subcomponent ✅
  • Through the ParentModule, it is less semantically correct, as even though the subcomponent is stated in ParentModule1, but it is still accessible by ParentModule2 ❎
@Module(subcomponents = [ChildComponent::class])
class ParentModule1
@Module
class ParentModule2 // Can still access to ChildComponent
@Component(modules = [ParentModule1::class, ParentModule2::class])
interface ServerComponent

4. Externally access to ChildComponent

  • Through the ParentComponent, external code that is not bounded inside Dagger Component could access the ChildComponent ✅
@Singleton
@Component
interface ParentComponent {
val childComponent: ChildComponent
}
fun main() {
// External code access the child component.
DaggerPareentComponent.create().childComponent
}
  • Through the ParentModule, external code that is not bounded insdie Dagger Component could not access the ChildComponent ❎

Of course you could have a hybrid as below. In this case, you need to have the Builder instead of the ChildComponent (since we need to have Builder defined within the ChildComponent as per comparison 2 above).

@Module(subcomponents = [ChildComponent::class])
class ParentModule
@Component(modules = [ParentModule::class])
interface ParentComponent {
val childComponentBuilder: ChildComponent.Builder
}

This also makes the subcomponents = [ChildComponent::class] redundant.

5. Injection of Modules into Subcomponent

  • Through the ParentComponent, we could still have module injection into the Subcomponent without the Builder ✅
@Module(subcomponents = [ChildComponent::class])
class ParentModule
@Component(modules = [ParentModule::class])
interface ParentComponent {
fun childComponent(childModule: ChildModule): ChildComponent
}

Of course if we have access to the ChildComponent’s Builder, then it would be done through the Builder as below.

  • Through the ParentModule, we need to have explicit have the API to inject the module. I feel this as boilerplate compare to previous one ❎
@Subcomponent(modules = [ChildModule::class])
interface ChildComponent {
@Subcomponent.Builder
interface Builder {
fun childModule(childModule: ChildModule): Builder
fun build(): ChildComponent
}

}

6. Reverse dependency (Parent access Child Component dependency)

This is elaborated in the below article. Both are able to do so.

TL;DR

Below would be my recommendation

  1. If your ChildComponent need to be access by external code (not bound to Dagger 2), then create the Subcomponent through the ParentComponent
  2. If your ChildComponent is definitely being used, you’ll not need to have it lazily create, then create the Subcomponent through the ParentComponent
  3. If your ChildComponent only used occasionally, and it’s all accessed only by the objects that is bounded by the ParentComponent, then create the Subcomponent through the ParentModule.

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