Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Demystifying Dagger

Demystifying Dagger

Dagger isn't magic, it simply generates boiler-plate code, similar to how we'd write it manually if we had to. In this talk, I discuss dependency injection, and we look at some code that Dagger generates to see how it works under the hood. This helps illustrate how Dagger works to break down its complex veneer and make it more understandable.

Ryan Harter

July 26, 2023
Tweet

More Decks by Ryan Harter

Other Decks in Technology

Transcript

  1. Dependency Injection 🗡 class CrashReporter Property("awesome") Backend(token = "abc123") private

    val userProp: Property private val backend: Backend = = { / / . .. }
  2. Dependency Injection 🗡 class CrashReporter private val userProp: Property private

    val backend: Backend = = { / / . .. } MyDependencies.property MyDependencies.backend
  3. class CrashReporter @Inject constructor( private val userProp: Property, private val

    backend: Backend, ) { // . .. } @Inject constructor userProp: Property backend: Backend Constructor Injection 🗡
  4. class CrashReporter @Inject constructor( private val userProp: Property, private val

    backend: Backend, ) { // . .. } @Inject constructor userProp: Property backend: Backend Constructor Injection 🗡
  5. class CrashReporter_Factory( private val userPropProvider: Provider<Property>, private val backendProvider: Provider<Backend>,

    ) : Provider<CrashReporter> { override fun get(): CrashReporter { return CrashReporter( userPropProvider.get(), backendProvider.get(), ) } } CrashReporter_Factory userPropProvider: Provider<Property> backendProvider: Provider<Backend> Provider<CrashReporter> override fun get(): CrashReporter CrashReporter( userPropProvider.get(), backendProvider.get(), ) Constructor Injection 🗡
  6. class CrashReporter_Factory( private val userPropProvider: Provider<Property>, private val backendProvider: Provider<Backend>,

    ) : Provider<CrashReporter> { override fun get(): CrashReporter { return CrashReporter( userPropProvider.get(), backendProvider.get(), ) } } CrashReporter_Factory userPropProvider: Provider<Property> backendProvider: Provider<Backend> Provider<CrashReporter> override fun get(): CrashReporter CrashReporter( userPropProvider.get(), backendProvider.get(), ) Constructor Injection 🗡
  7. class MyFragment_MembersInjector( private val crashReporterProvider: Provider<CrashReporter>, ) : MembersInjector<MyFragment> {

    override fun injectMembers(instance: MyFragment) { instance.crashReporter = crashReporterProvider.get() } } MyFragment_MembersInjector MembersInjector<MyFragment> private val crashReporterProvider: Provider<CrashReporter> override fun injectMembers(instance: MyFragment) instance.crashReporter = crashReporterProvider.get() Member Injection 🗡
  8. class MyFragment_MembersInjector( private val crashReporterProvider: Provider<CrashReporter>, ) : MembersInjector<MyFragment> {

    override fun injectMembers(instance: MyFragment) { instance.crashReporter = crashReporterProvider.get() } } MyFragment_MembersInjector MembersInjector<MyFragment> private val crashReporterProvider: Provider<CrashReporter> override fun injectMembers(instance: MyFragment) instance.crashReporter = crashReporterProvider.get() Member Injection 🗡
  9. @Module class CrashModule { @Provides fun provideBackend(token: ApiToken): Backend {

    return Backend(token) } } @Module class CrashModule { @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) Provider Injection 🗡
  10. @Module @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) :

    { } class CrashModule { abstract Provider Injection 🗡
  11. @Module @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) :

    { } class CrashModule { abstract Provider Injection 🗡
  12. @Module @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) :

    { } class CrashModule { abstract @Binds Provider Injection 🗡
  13. @Module @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) :

    { } class CrashModule { abstract @Binds abstract fun bindService() Provider Injection 🗡
  14. @Module @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) :

    { } class CrashModule { abstract @Binds abstract fun bindService(backend: Backend) Provider Injection 🗡
  15. @Module @Provides } fun provideBackend(token: ApiToken) Backend return Backend(token) :

    { } class CrashModule { abstract @Binds abstract fun bindService(backend: Backend): Service Provider Injection 🗡
  16. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  17. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  18. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  19. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  20. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  21. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  22. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  23. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  24. { { CrashModule_ProvideBackendFactory ) } } class ( private val

    module: CrashModule, , private val tokenProvider: Provider<ApiToken> Provider<Backend?> : override fun get(): Backend return module.provideBackend( ) tokenProvider.get() Provider Injection 🗡
  25. @Module class CrashModule { } @Provides return Backend(token) } ):

    Backend { ApiToken String Qualifiers 🗡 fun provideBackend(token:
  26. @Module class CrashModule { } @Provides return Backend(token) } ):

    Backend { ApiToken String Qualifiers 🗡 fun provideBackend(token:
  27. @Module class CrashModule { } @Provides return Backend(token) } ):

    Backend { String @Provides fun provideApiToken(): String = "abcd" @ApiToken fun provideBackend( token: @ApiToken Qualifiers 🗡
  28. class DaggerAppComponent { DaggerAppComponent companion object { fun builder(): Builder

    { // .. . } } class Builder { // ... fun build(): AppComponent { // .. . } } private class AppComponentImpl : AppComponent { // .
  29. class DaggerAppComponent { DaggerAppComponent companion object { fun builder(): Builder

    { // .. . } } class Builder { // ... fun build(): AppComponent { // .. . } } private class AppComponentImpl : AppComponent { .
  30. class DaggerAppComponent { DaggerAppComponent private class AppComponentImpl : AppComponent {

    // Providers private val userPropProvider: Provider<Property> private val backendProvider: Provider<Backend> private val tokenProvider: Provider<ApiToken> private val crashReporterProvider: Provider<CrashReporter> // MembersInjectors private val myFragmentMembersInjector: MembersInjector<MyFragment> } } .
  31. class DaggerAppComponent { DaggerAppComponent private class AppComponentImpl : AppComponent {

    // Providers private val userPropProvider: Provider<Property> private val backendProvider: Provider<Backend> private val tokenProvider: Provider<ApiToken> private val crashReporterProvider: Provider<CrashReporter> // MembersInjectors private val myFragmentMembersInjector: MembersInjector<MyFragment> } } .
  32. class DaggerAppComponent { DaggerAppComponent private class AppComponentImpl : AppComponent {

    // Providers private val userPropProvider: Provider<Property> private val backendProvider: Provider<Backend> private val tokenProvider: Provider<ApiToken> private val crashReporterProvider: Provider<CrashReporter> // MembersInjectors private val myFragmentMembersInjector: MembersInjector<MyFragment> } } myFragmentMembersInjector.injectMembers(instance) }
  33. @Component(modules = [CrashModule :: class]) interface AppComponent { } fun

    inject(instance: MyFragment) val crashReporter: CrashReporter
  34. class ScopedProvider<T>( private val implProvider: Provider<T> ) : Provider<T> {

    private var instance: T? = null override fun get(): T { if (instance = = null) { instance = implProvider.get() } return instance } }
  35. private class AppComponentImpl : AppComponent { // Providers private val

    userPropProvider: Provider<Property> private val backendProvider: Provider<Backend> private val tokenProvider: Provider<ApiToken> private val crashReporterProvider: Provider<CrashReporter> // MembersInjectors private val myFragmentMembersInjector: MembersInjector<MyFragment> } } myFragmentMembersInjector.injectMembers(instance) } override val crashReporter: CrashReporter get() = crashReporterProvider.get()
  36. private class AppComponentImpl : AppComponent { // . .. ,

    crashReporterProvider: Provider<CrashReporter>, ) { // . .. this.crashReporterProvider = } crashReporterProvider
  37. private class AppComponentImpl : AppComponent { // . .. ,

    crashReporterProvider: Provider<CrashReporter>, ) { // . .. this.crashReporterProvider = } ScopedProvider(crashReporterProvider) crashReporterProvider
  38. { } fun inject(instance: MyFragment) fun inject(instance: ListActivity) fun inject(instance:

    ItemListFragment) fun inject(instance: ItemDetailFragment) fun inject(instance: ShareFragment) fun inject(instance: AccountActivity) fun inject(instance: FriendsFragment) fun inject(instance: SettingsActivity) @Component(modules = [CrashModule :: class]) interface AppComponent ⚒
  39. { } fun inject(instance: MyFragment) fun inject(instance: ListActivity) fun inject(instance:

    ItemListFragment) fun inject(instance: ItemDetailFragment) fun inject(instance: ShareFragment) fun inject(instance: AccountActivity) fun inject(instance: FriendsFragment) fun inject(instance: SettingsActivity) @Component(modules = [ CrashModule :: class ]) interface AppComponent , AnalyticsModule :: class, NetworkModule : : class BillingModule : : class DatabaseModule :: class FileModule :: class UserModule :: class , , , , , ⚒
  40. @Component(modules = [ CrashModule :: class ]) interface AppComponent ,

    AnalyticsModule :: class, NetworkModule : : class BillingModule : : class DatabaseModule :: class FileModule :: class UserModule :: class , , , , , ⚒ : MyFragmentInjector, ListActivityInjector, ItemListFragmentInjector, ItemDetailFragmentInjector, ShareFragmentInjector, AccountActivityInjector, FriendsFragmentInjector, SettingsActivityInjector,
  41. @Component(modules = [ CrashModule :: class ]) interface AppComponent ,

    AnalyticsModule :: class, NetworkModule : : class BillingModule : : class DatabaseModule :: class FileModule :: class UserModule :: class , , , , , ⚒ : MyFragmentInjector, ListActivityInjector, ItemListFragmentInjector, ItemDetailFragmentInjector, ShareFragmentInjector, AccountActivityInjector, FriendsFragmentInjector, SettingsActivityInjector, @MergeComponent(scope = AppObjectGraph :
  42. ⚒ @Module interface CrashModule { @Binds } fun bindCrashReporter(impl: RealCrashReporter):

    CrashReporter @ContributesTo(AppObjectGraph :: class) class RealCrashReporter @Inject constructor( private val userProp: Property, private val backend: Backend, ): CrashReporter { // . .. }