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

Dagger Party Tricks

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Zac Sweers Zac Sweers
February 19, 2019

Dagger Party Tricks

Neat things you can do with dagger and common libraries/patterns in modern android development.

Given at Londroid on 2019/02/19 and Droidcon NYC on 2019/08/26

Avatar for Zac Sweers

Zac Sweers

February 19, 2019
Tweet

More Decks by Zac Sweers

Other Decks in Programming

Transcript

  1. @Provides fun provideClient(): OkHttpClient { return OkHttpClient.Builder() .build() }b @Provides

    fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a
  2. @Provides fun provideCache(ctx: Context): Cache { return Cache(ctx.cacheDir, CACHE_SIZE) }c

    @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a
  3. @Provides fun provideCache(ctx: Context): Cache { return Cache(ctx.cacheDir, CACHE_SIZE) }c

    @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a
  4. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Retrofit )e
  5. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Retrofit )e
  6. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Retrofit )e
  7. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Retrofit )e
  8. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a 100-150ms! @Inject constructor( retrofit: Retrofit )e
  9. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a 100-150ms! @Inject constructor( retrofit: Retrofit )e
  10. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Lazy<Retrofit> )e 100-150ms!
  11. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Lazy<Retrofit> )e 100-150ms! retrofit.get().create(...)
  12. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Lazy<Retrofit> )e 100-150ms! retrofit.get().create(...)
  13. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Lazy<Retrofit> )e 100-150ms! retrofit.get().create(...)
  14. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit(client: OkHttpClient): Retrofit { return Retrofit.Builder() .client(client) .build() }a @Inject constructor( retrofit: Lazy<Retrofit> )e 100-150ms! retrofit.get().create(...) Main thread!
  15. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit( client: Lazy<OkHttpClient>): Retrofit { return Retrofit.Builder() .callFactory { client.get().newCall(it) } .build() }a @Inject constructor( retrofit: Retrofit )e 100-150ms! Background thread
  16. Courtesy of Nick Butcher (@crafty) @Provides fun provideCache(ctx: Context): Cache

    { checkMainThread() return Cache(ctx.cacheDir, CACHE_SIZE) }c @Provides fun provideClient(cache: Cache): OkHttpClient { checkMainThread() return OkHttpClient.Builder() .cache(cache) .build() }b @Provides fun provideRetrofit( client: Lazy<OkHttpClient>): Retrofit { return Retrofit.Builder() .callFactory { client.get().newCall(it) } .build() }a @Inject constructor( retrofit: Retrofit )e 100-150ms! Background thread
  17. @Module class MyGiantModule { @Provides fun provideSeasoning() = Seasoning() @Provides

    fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }a
  18. @Module class MyGiantModuleBase { @Provides fun provideSeasoning() = Seasoning() }a

    @Module(includes = MyGiantModuleBase::class) class MyGiantModule { @Provides fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }b
  19. @Module(includes = MyGiantModuleBase::class) class MyGiantModule { @Provides fun provideTaco(seasoning: Seasoning)

    = Taco(seasoning) }b @Module class MyGiantModuleBase { @Provides fun provideSeasoning() = Seasoning() }a
  20. @Module class MyGiantModule { @Provides fun provideSeasoning() = Seasoning() @Provides

    fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }a
  21. @Module class SeasoningModule { @Provides fun provideSeasoning() = Seasoning() }b

    @Module(includes = SeasoningModule::class) class MyGiantModule { @Provides fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }a
  22. @Module class SeasoningModule { @Provides fun provideSeasoning() = Seasoning() }b

    @Module(includes = [SeasoningModule::class, TacoModule::class]) class MyGiantModule @Module class TacoModule { @Provides fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }c
  23. @Module class SeasoningModule { @Provides fun provideSeasoning() = Seasoning() }b

    @Module(includes = TacoModule::class) class MyGiantModule @Module(includes = SeasoningModule::class) class TacoModule { @Provides fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }c
  24. @Module class SeasoningModule { @Provides fun provideSeasoning() = Seasoning() }b

    @Module(includes = SeasoningModule::class) class TacoModule { @Provides fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }c
  25. @Module class FoodModule { @Provides fun provideSeasoning() = Seasoning() @Provides

    fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }
  26. @Qualifier private annotation class InternalApi @Module class FoodModule { @Provides

    fun provideSeasoning() = Seasoning() @Provides fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }a
  27. @Qualifier private annotation class InternalApi @Module class FoodModule { @InternalApi

    @Provides fun provideSeasoning() = Seasoning() @Provides fun provideTaco(@InternalApi seasoning: Seasoning) = Taco(seasoning) }a
  28. @Module class FoodModule { @Provides fun provideSeasoning() = Seasoning() @Provides

    fun provideTaco(seasoning: Seasoning) = Taco(seasoning) }a
  29. @Module class FoodModule { @Provides fun provideSpicy() = SpicySeasoning() @Provides

    fun provideElPaso() = ElPasoSeasoning() @Provides fun provideTaco( spicy: SpicySeasoning, elpaso: ElPasoSeasoning ) = Taco(setOf(spicy, elpaso)) }a
  30. @Module abstract class FoodModule { @Multibinds abstract fun seasonings(): Set<Seasoning>

    @Provides fun provideSpicy() = SpicySeasoning() @Provides fun provideElPaso() = ElPasoSeasoning() @Provides fun provideTaco( spicy: SpicySeasoning, elpaso: ElPasoSeasoning ) = Taco(setOf(spicy, elpaso)) }a
  31. @Module abstract class FoodModule { @Multibinds abstract fun seasonings(): Set<Seasoning>

    @Provides @IntoSet fun provideSpicy() = SpicySeasoning() @Provides @IntoSet fun provideElPaso() = ElPasoSeasoning() @Provides fun provideTaco(seasonings: Set<Seasoning>) = Taco(seasonings) }a
  32. @Module(includes = SeasoningModule::class) abstract class FoodModule { @Multibinds abstract fun

    seasonings(): Set<Seasoning> @Provides fun provideTaco(seasonings: Set<Seasoning>) = Taco(seasonings) }a @Module class SeasoningModule { @Provides @IntoSet fun provideSpicy() = SpicySeasoning() @Provides @IntoSet fun provideElPaso() = ElPasoSeasoning() }
  33. @Module abstract class FoodModule { @Multibinds abstract fun seasonings(): Set<Seasoning>

    @Provides fun provideTaco(seasonings: Set<Seasoning>) = Taco(seasonings) }a
  34. @Module abstract class NetworkModule { @Multibinds abstract fun interceptors(): Set<Interceptor>

    @Provides fun provideOkHttp(interceptors: Set<Interceptors>) = // ... }a
  35. @Module abstract class DataModule { @Multibinds abstract fun adapters(): Set<JsonAdapter>

    @Provides fun provideMoshi(adapters: Set<JsonAdapter>) = // ... }a
  36. data class ScreenKey( val id: String, val xpId: String )a

    class ScreenPresenter @Inject constructor( screens: Map<ScreenKey, Provider<Screen>>, private val xpManager: XpManager ) { private val finalScreens = screens.filterKeys { xpManager.isEnabled(it.xpId) } }
  37. Dagger Party Tricks • github.com/ZacSweers/CatchUp • github.com/JakeWharton/sdksearch • github.com/JakeWharton/u2020 •

    Dagger Powered Plugin System post: https:// bit.ly/2T2Yqkl • Dependency Injection in a multi module project: https://bit.ly/2Gz5YFR @ZacSweers