Skip to content

Dagger ‐ Scoping using module

Devrath edited this page Oct 8, 2023 · 11 revisions

Observations

  • In the code below you can see an ActivityComponent which has a dependency of ApplicationComponent.
  • Here, We can get instances of ApplicationComponent in the ActivityComponent.
  • Now in the usage say for example it is an activity where we are constructing the component, we can just construct the ActivityComponent and access the instances of all the ApplicationComponent but we need to mention the function in ApplicationComponent that exposes that instance.
  • Explicitly exposing the instance type is also a drawback because say we have a lot of instances in the parent component as a dependency, Then we might have to explicitly expose them in the child component. This can be solved by sub-components.

Output

// -------- Application loaded for the first time and we initiated component building
analyticsService reference ->206413843
analyticsService1 reference ->206413843
imageService reference ->169207152
imageService1 reference ->169207152
Injected
// -------- Application is already loaded and we initiate component building a second time
analyticsService reference ->206413843
analyticsService1 reference ->206413843
imageService reference ->169207152
imageService1 reference ->169207152
Injected
// -------- Application is already loaded but we now rotate the screen and initiate component building a third time
analyticsService reference ->206413843
analyticsService1 reference ->206413843
imageService reference ->150255858
imageService1 reference ->150255858
Injected

Code

Scopes

ActivityScope.kt

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

Implementations

AnalyticsService.kt

class AnalyticsService {
    fun trackEvent(action:String){
        PrintUtils.printLog("Analytics service has tracked your action:-> $action")
    }
}

ImageProcessingService.kt

class ImageProcessingService {
    fun initiateImageProcessing(){
        PrintUtils.printLog("Image processing is initiated")
    }
}

Modules

AnalyticsServiceModule.kt

@Module
@DisableInstallInCheck
class AnalyticsServiceModule {
    @Singleton
    @Provides
    fun provideAnalyticsService() : AnalyticsService {
        return AnalyticsService()
    }
}

ImageProcessingServiceModule.kt

@Module
@DisableInstallInCheck
class ImageProcessingServiceModule {
    @ActivityScope
    @Provides
    fun provideImageProcessingService() : ImageProcessingService {
        return ImageProcessingService();
    }
}

Components

ApplicationComponent.kt

@Singleton
@Component(modules = [AnalyticsServiceModule::class])
interface ApplicationComponent {
    fun provideAnalytics() : AnalyticsService
}

ActivityComponent.kt

@ActivityScope
@Component(dependencies = [ApplicationComponent::class], modules = [ImageProcessingServiceModule::class])
interface ActivityComponent {

    fun provideAnalytics() : AnalyticsService
    fun provideImageProcessingService() : ImageProcessingService

}

Application

DiApplication.kt

@HiltAndroidApp
class DiApplication : Application() {

    private lateinit var connComp : ConnectionComponent

    override fun onCreate() {
        super.onCreate()
        connComp = DaggerConnectionComponent.builder().build()
    }

    fun provideApplicationComponent(): ApplicationComponent { return appComponent }
}

Activity

class MyActivity : AppCompatActivity() {

    private lateinit var binding: ActivityCustomScopeBinding

    private lateinit var component : ActivityComponent

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

        component =  DaggerActivityComponent.builder()
            .applicationComponent((application as DiApplication).provideApplicationComponent())
            .imageProcessingServiceModule(ImageProcessingServiceModule())
            .build()

        testReferences();
    }

    private fun setOnClickListeners() {

        binding.apply {
            initiateUsingModuleId.setOnClickListener {
                testReferences()
            }
        }
    }

    private fun testReferences() {
        val analyticsService = component.provideAnalytics()
        val analyticsService1 = component.provideAnalytics()
        val imageService = component.provideImageProcessingService()
        val imageService1 = component.provideImageProcessingService()
        PrintUtils.printLog("analyticsService reference ->" + analyticsService.hashCode().toString())
        PrintUtils.printLog("analyticsService1 reference ->" + analyticsService1.hashCode().toString())
        PrintUtils.printLog("imageService reference ->" + imageService.hashCode().toString())
        PrintUtils.printLog("imageService1 reference ->" + imageService1.hashCode().toString())
        PrintUtils.printLog("Injected")
    }

}
Clone this wiki locally