Skip to content

Dagger ‐ Using sub‐components with the factory way

Devrath edited this page Oct 8, 2023 · 4 revisions

Observations

  • Let's take the example below mentioned here where we mention the userComponent at the application level. It has the scope of the entire application
  • In the UserComponent we mention the access to the subcomponent using the Class.Factory way and keep the reference.
  • In the child-component we mention the component as @Subcomponent indicating it as the child component.
  • In the activity we can access the parent component and using the factory reference kept, we shall access the child component.
  • Also the factory way of implementing the child sub-component is better than the builder way since we do not need to mention the method in the factory as we do in the builder.

Output

Phone is started for the user Superman

Code

Scopes

ActivityScope.kt

@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class ActivityScope

Implementations

Battery.kt

class Battery @Inject constructor() {
    fun charging(){
        PrintUtils.printLog("Battery is charging !")
    }
}

Screen.kt

class Screen @Inject constructor() {
    fun displayInformation(){
        PrintUtils.printLog("Screen is displayed !")
    }
}

Phone.kt

class Phone @Inject constructor(
    val battery: Battery, val screen: Screen, val user : User
) {
    fun startPhone(){
        PrintUtils.printLog("Phone is started for the user ${user.name}")
    }
}

User.kt

data class User(val name:String)

Modules

PhoneModule.kt

@Module
@DisableInstallInCheck
class PhoneModule {
    @ActivityScope
    @Provides
    fun providePhone(battery: Battery, screen: Screen, user: User) : Phone {
        return Phone(battery,screen,user)
    }
}

UserModule.kt

@Module
@DisableInstallInCheck
class UserModule {
    @Singleton
    @Provides
    fun provideUser() : User {
        return User(name = "Superman")
    }
}

Components

PhoneComponent.kt

@ActivityScope
@Subcomponent(modules = [PhoneModule::class])
interface PhoneComponent {
    fun inject(activity: MyActivity)

    @Subcomponent.Factory
    interface Factory{
        fun create() : PhoneComponent
    }
}

UserComponent.kt

@Singleton
@Component(modules = [UserModule::class])
interface UserComponent {
    fun getPhoneComponentFactory() : PhoneComponent.Factory
}

DiApplication

DiApplication.kt

@HiltAndroidApp
class DiApplication : Application() {

    private lateinit var userComponent : UserComponent

    override fun onCreate() {
        super.onCreate()
        userComponent = DaggerUserComponent.builder().build()
    }
    fun provideDaggerUserComponent(): UserComponent { return userComponent }
}

Activity

class MyActivity : AppCompatActivity() {

    private lateinit var binding: ActivityDaggerSubComponentsFactoryBinding

    @Inject lateinit var phone : Phone

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityDaggerSubComponentsFactoryBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setOnClickListeners();
    }

    private fun setOnClickListeners() {
        binding.apply {
            initiateId.setOnClickListener {
                val userComp = (application as DiApplication).provideDaggerUserComponent()
                val phoneComp = userComp.getPhoneComponentFactory().create()
                phoneComp.inject(this@DaggerSubComponentsFactoryActivity)

                phone.startPhone()
            }
        }
    }
}
Clone this wiki locally