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

It's complicated, but it doesn't have to be: a ...

It's complicated, but it doesn't have to be: a Dagger journey

https://www.youtube.com/watch?v=9fn5s8_CYJI

Dagger is a complex tool, we can all agree on that. It's also the most performant and scalable dependency injector we have available -- no wonder it's the official recommendation from Google when it comes to dependency injection for Android apps. And yet, we keep looking for simpler alternatives (usually service locators) just so we don't have to deal with it.

Even thought Dagger is complex, it doesn't have to be complicated. It's possible to keep things simple and still take advantage of what it offers at its core. There are many ways to setup Dagger, and believe it or not, some of them are quite simple. The goal of this talk is to present a simplistic approach to Dagger, where we can take advantage of dependency injection with minimal boilerplate and optimum performance. On top of that, we'll be looking in details on best practices and how to ensure you're taking the most out of Dagger.

Join me if you've had unpleasant experiences with Dagger -- or even if you're happy with your current setup -- so we can take a fresh look on how we can work with it. And if you haven't worked with Dagger before, this is the perfect opportunity to get off on the right foot!

https://androidmakers.fr/schedule/?sessionId=YYF-6635

Fred Porciúncula

April 23, 2019
Tweet

More Decks by Fred Porciúncula

Other Decks in Programming

Transcript

  1. It's complicated, but it doesn't have to be: a Dagger

    journey ⚔ Fred Porciúncula @tfcporciuncula
  2. public abstract class ObjectGraph { public static ObjectGraph create(Object... modules)

    {} public abstract ObjectGraph plus(Object... modules); public abstract void validate(); public abstract void injectStatics(); public abstract <T> T get(Class<T> type); public abstract <T> T inject(T instance); } public @interface Module { Class<?>[] injects() default {}; Class<?>[] staticInjections() default {}; Class<?>[] includes() default {}; Class<?> addsTo() default Void.class; boolean overrides() default false; boolean complete() default true; boolean library() default true; } public @interface Provides { enum Type { UNIQUE, SET } Type type() default Type.UNIQUE; } public interface Lazy<T> { T get(); } public interface MembersInjector<T> { void injectMembers(T instance); } " From The Future of Dependency Injection with Dagger 2 by Jake Wharton
  3. public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies()

    default {}; } public @interface Module { Class<?>[] includes() default {}; } public @interface Provides { } public @interface MapKey { boolean unwrapValue(); } ⚔ From The Future of Dependency Injection with Dagger 2 by Jake Wharton
  4. public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies()

    default {}; @interface Builder {} @interface Factory {} } public @interface Subcomponent { Class<?>[] modules() default {}; @interface Builder {} @interface Factory {} } public @interface Module { Class<?>[] includes() default {}; Class<?>[] subcomponents() default {} } public @interface BindsInstance {} public @interface Binds {} public @interface BindsOptionalOf {} public @interface Reusable {} public @interface Provides {} public @interface IntoSet {} public @interface ElementsIntoSet {} public @interface IntoMap {} public @interface ClassKey { Class<?> value(); } public @interface MapKey { boolean unwrapValue(); } ⚔
  5. class BusinessUtil @Inject constructor() { ... } class BusinessRunner @Inject

    constructor( private val businessUtil: BusinessUtil ) { ... }
  6. class BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) {

    ... } class BusinessUtil @Inject constructor() { ... }
  7. class BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) {

    ... } class BusinessUtil @Inject constructor() { ... } @Singleton class BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... }
  8. class BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) {

    ... } class BusinessUtil @Inject constructor() { ... } @Reusable class BusinessUtil @Inject constructor() { ... } @Singleton class BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... }
  9. @Reusable class BusinessUtil @Inject constructor() { ... } @Singleton class

    BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... }
  10. @Singleton @Component interface ApplicationComponent { } @Component interface ApplicationComponent {

    val businessRunner: BusinessRunner } DaggerApplicationComponent.create()
  11. @Singleton @Component interface ApplicationComponent { } @Component interface ApplicationComponent {

    val businessRunner: BusinessRunner } DaggerApplicationComponent.create() DaggerApplicationComponent.create().businessRunner
  12. @Singleton @Component interface ApplicationComponent { } @Component interface ApplicationComponent {

    val businessRunner: BusinessRunner } DaggerApplicationComponent.create() DaggerApplicationComponent.create().businessRunner DaggerApplicationComponent.create().businessRunner.doBusiness()
  13. @Singleton DaggerApplicationComponent.create() DaggerApplicationComponent.create().businessRunner DaggerApplicationComponent.create().businessRunner.doBusiness() @Component @Singleton interface ApplicationComponent { val

    businessRunner: BusinessRunner fun inject(activity: BusinessActivity) } DaggerApplicationComponent.create().businessRunner.doBusiness() class BusinessActivity : AppCompatActivity() { @Inject lateinit var businessRunner: BusinessRunner }
  14. @Singleton DaggerApplicationComponent.create() DaggerApplicationComponent.create().businessRunner DaggerApplicationComponent.create().businessRunner.doBusiness() @Component @Singleton interface ApplicationComponent { val

    businessRunner: BusinessRunner fun inject(activity: BusinessActivity) } DaggerApplicationComponent.create().businessRunner.doBusiness() class BusinessActivity : AppCompatActivity() { @Inject lateinit var businessRunner: BusinessRunner } DaggerApplicationComponent.create().inject(this)
  15. @Component @Singleton interface ApplicationComponent { fun inject(activity: BusinessActivity) } @Inject

    lateinit var businessRunner: BusinessRunner DaggerApplicationComponent.create().inject(this)
  16. @Component @Singleton interface ApplicationComponent { fun inject(activity: BusinessActivity) } @Inject

    lateinit var businessRunner: BusinessRunner DaggerApplicationComponent.create().inject(this) @Component @Singleton interface ApplicationComponent { fun inject(activity: BusinessActivity) } @Inject lateinit var businessRunner: BusinessRunner DaggerApplicationComponent.create().inject(this)
  17. @Component @Singleton interface ApplicationComponent { fun inject(activity: BusinessActivity) } @Inject

    lateinit var businessRunner: BusinessRunner DaggerApplicationComponent.create().inject(this) @Component @Singleton interface ApplicationComponent { val businessRunner: BusinessRunner } private val businessRunner = DaggerApplicationComponent.create().businessRunner @Component @Singleton interface ApplicationComponent { fun inject(activity: BusinessActivity) } @Inject lateinit var businessRunner: BusinessRunner DaggerApplicationComponent.create().inject(this) @Component @Singleton interface ApplicationComponent { fun inject(activity: BusinessActivity) } @Inject lateinit var businessRunner: BusinessRunner DaggerApplicationComponent.create().inject(this)
  18. @Component interface ApplicationComponent { val businessRunner: BusinessRunner } @Component interface

    ApplicationComponent { fun inject(activity: MainActivity1) fun inject(activity: MainActivity2) fun inject(activity: MainActivity3) fun inject(activity: MainActivity4) fun inject(activity: MainActivity5) }
  19. @Component interface ApplicationComponent { val businessRunner1: BusinessRunner1 val businessRunner2: BusinessRunner2

    val businessRunner3: BusinessRunner3 val businessRunner4: BusinessRunner4 val businessRunner5: BusinessRunner5 } @Component interface ApplicationComponent { fun inject(activity: MainActivity) }
  20. class MainActivity : AppCompatActivity() { @Inject lateinit var businessRunner1: BusinessRunner1

    @Inject lateinit var businessRunner2: BusinessRunner2 @Inject lateinit var businessRunner3: BusinessRunner3 @Inject lateinit var businessRunner4: BusinessRunner4 @Inject lateinit var businessRunner5: BusinessRunner5 ... }
  21. @Reusable class BusinessUtil @Inject constructor() { ... } @Singleton class

    BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... } @Singleton @Component interface ApplicationComponent { val businessRunner: BusinessRunner } private val businessRunner = DaggerApplicationComponent.create().businessRunner
  22. @Reusable class BusinessUtil @Inject constructor() { ... } @Singleton class

    BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... } @Singleton @Component interface ApplicationComponent { val businessRunner: BusinessRunner } private val businessRunner = DaggerApplicationComponent.create().businessRunner @Singleton @Component interface ApplicationComponent { val businessRunner: BusinessRunner } private val businessRunner = DaggerApplicationComponent.create().businessRunner
  23. @Reusable class BusinessUtil @Inject constructor() { ... } @Singleton class

    BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... } @Singleton @Component interface ApplicationComponent { val businessRunner: BusinessRunner } private val businessRunner = DaggerApplicationComponent.create().businessRunner @Reusable class BusinessUtil @Inject constructor() { ... } @Singleton class BusinessRunner @Inject constructor( private val businessUtil: BusinessUtil ) { ... }
  24. class MyApplication : Application() { } companion object { lateinit

    var component: ApplicationComponent private set }
  25. class MyApplication : Application() { } companion object { lateinit

    var component: ApplicationComponent private set } override fun onCreate() { super.onCreate() component = DaggerApplicationComponent.create() }
  26. class MyApplication : Application() { } companion object { lateinit

    var component: ApplicationComponent private set } override fun onCreate() { super.onCreate() component = DaggerApplicationComponent.create() } class MyActivity : AppCompatActivity() { private val businessRunner = MyApplication.component.businessRunner } companion object { lateinit var component: ApplicationComponent private set } override fun onCreate() { super.onCreate() component = DaggerApplicationComponent.create() } class MyApplication : Application() { }
  27. class MyApplication : Application() { val component by lazy {

    DaggerApplicationComponent.create() } }
  28. interface ComponentProvider { val component: ApplicationComponent } class MyApplication :

    Application() { val component by lazy { DaggerApplicationComponent.create() } }
  29. class MyApplication : Application(), ComponentProvider { override val component by

    lazy { DaggerApplicationComponent.create() } } interface ComponentProvider { val component: ApplicationComponent }
  30. class MyApplication : Application(), ComponentProvider { override val component by

    lazy { DaggerApplicationComponent.create() } } interface ComponentProvider { val component: ApplicationComponent } val Activity.injector get() = (application as ComponentProvider).component
  31. class MyApplication : Application(), ComponentProvider { override val component by

    lazy { DaggerApplicationComponent.create() } } interface ComponentProvider { val component: ApplicationComponent } val Activity.injector get() = (application as ComponentProvider).component class MyActivity : AppCompatActivity() { private val businessRunner by lazy { injector.businessRunner } } val Activity.injector get() = (application as ComponentProvider).component class MyApplication : Application(), ComponentProvider { override val component by lazy { DaggerApplicationComponent.create() } } interface ComponentProvider { val component: ApplicationComponent }
  32. @Module object SharedPreferencesModule { } @JvmStatic @Provides fun provideLogSharedPreferences(context: Context)

    = context.getSharedPreferences( context.getString(R.string.log_preferences_name), Context.MODE_PRIVATE )
  33. @Module object SharedPreferencesModule { } @JvmStatic @Provides fun provideLogSharedPreferences(context: Context)

    = context.getSharedPreferences( context.getString(R.string.log_preferences_name), Context.MODE_PRIVATE ) @Component(modules = [SharedPreferencesModule::class]) interface ApplicationComponent { ... }
  34. @Module object SharedPreferencesModule { } @JvmStatic @Provides fun provideLogSharedPreferences(context: Context)

    = context.getSharedPreferences( context.getString(R.string.log_preferences_name), Context.MODE_PRIVATE ) @Component(modules = [SharedPreferencesModule::class]) interface ApplicationComponent { ... } @Component(modules = [SharedPreferencesModule::class]) interface ApplicationComponent { ... }
  35. @Module object SharedPreferencesModule { } @JvmStatic @Provides fun provideLogSharedPreferences(context: Context)

    = context.getSharedPreferences( context.getString(R.string.log_preferences_name), Context.MODE_PRIVATE )
  36. @Module object SharedPreferencesModule { } @JvmStatic @Provides fun provideLogSharedPreferences(context: Context)

    = context.getSharedPreferences( context.getString(R.string.log_preferences_name), Context.MODE_PRIVATE ) @JvmStatic @Provides fun provideLogSharedPreferences(context: Context) = context.getSharedPreferences( context.getString(R.string.log_preferences_name), Context.MODE_PRIVATE ) @Module object SharedPreferencesModule { }
  37. @Component(modules = [ApplicationModule::class]) interface ApplicationComponent { ... } @Module class

    ApplicationModule(private val applicationContext: Context) { @Provides fun provideApplicationContext() = applicationContext }
  38. @Component(modules = [ApplicationModule::class]) interface ApplicationComponent { ... } @Module class

    ApplicationModule(@get:Provides val applicationContext: Context) DaggerApplicationComponent .builder() .applicationModule(ApplicationModule(applicationContext)) .build() @Component(modules = [ApplicationModule::class]) interface ApplicationComponent { ... } @Module class ApplicationModule(@get:Provides val applicationContext: Context)
  39. @Component interface ApplicationComponent { ... } @Component.Builder interface Builder {

    } ... } @Component.Builder interface Builder { fun build(): ApplicationComponent } ... }
  40. @Component interface ApplicationComponent { ... } @Component.Builder interface Builder {

    } ... } @Component.Builder interface Builder { fun build(): ApplicationComponent } ... } @Component interface ApplicationComponent { @Component.Builder interface Builder { @BindsInstance fun applicationContext(applicationContext: Context): Builder fun build(): ApplicationComponent } ... }
  41. @Component.Builder interface Builder { @BindsInstance fun applicationContext(applicationContext: Context): Builder fun

    build(): ApplicationComponent } ... } DaggerApplicationComponent .builder() .applicationContext(applicationContext) .build()
  42. @Component interface ApplicationComponent { ... } @Component interface ApplicationComponent {

    @Component.Factory interface Factory { } @Component interface ApplicationComponent { @Component.Factory interface Factory { fun create( @BindsInstance applicationContext: Context ): ApplicationComponent }
  43. interface Factory { fun create( @BindsInstance applicationContext: Context ): ApplicationComponent

    } ... } DaggerApplicationComponent .factory() .create(applicationContext)
  44. Use the new @Component.Factory Tip #5 And avoid the lame

    module with constructor arguments or the old @Component.Builder
  45. dagger-android • Great for that setup • Still verbose •

    Real DI • Member injection • Decouples injection sites from injector
  46. dagger-android • Great for that setup • Still verbose •

    Real DI • Member injection • Decouples injection sites from injector Doesn’t work with dynamic features
  47. class MyViewModel( private val businessRunner: BusinessRunner ) : ViewModel() {

    ... } class MyViewModelFactory( private val businessRunner: BusinessRunner ) : ViewModelProvider.Factory { }
  48. class MyViewModel( private val businessRunner: BusinessRunner ) : ViewModel() {

    ... } class MyViewModelFactory( private val businessRunner: BusinessRunner ) : ViewModelProvider.Factory { } class MyViewModelFactory( private val businessRunner: BusinessRunner ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = MyViewModel(businessRunner) as T }
  49. class MyViewModel( private val businessRunner: BusinessRunner ) : ViewModel() {

    ... } class MyViewModelFactory @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = MyViewModel(businessRunner) as T }
  50. @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory } private

    val myViewModel by lazy { ViewModelProviders .of(this, injector.myViewModelFactory) .get(MyViewModel::class.java) }
  51. @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory } private

    val myViewModel by lazy { ViewModelProviders .of(this, injector.myViewModelFactory) .get(MyViewModel::class.java) } private val myViewModel by lazy { ViewModelProviders .of(this, injector.myViewModelFactory) .get(MyViewModel::class.java) }
  52. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { ... } class MyViewModelFactory @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = MyViewModel(businessRunner) as T }
  53. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { ... } class MyViewModelFactory<T : ViewModel> @Inject constructor( private val viewModel: Provider<T> ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = MyViewModel(businessRunner) as T } class MyViewModelFactory<T : ViewModel> @Inject constructor( private val viewModel: Provider<T> ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = MyViewModel(businessRunner) as T }
  54. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { ... } class MyViewModelFactory<T : ViewModel> @Inject constructor( private val viewModel: Provider<T> ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = viewModel.get() as T } class MyViewModelFactory<T : ViewModel> @Inject constructor( private val viewModel: Provider<T> ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = viewModel.get() as T }
  55. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { ... } class MyViewModelFactory<T : ViewModel> @Inject constructor( private val viewModel: Provider<T> ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>) = viewModel.get() as T }
  56. @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory } @Component

    interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory<MyViewModel> }
  57. @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory } @Component

    interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory<MyViewModel> } private val myViewModel by lazy { ViewModelProviders .of(this, injector.myViewModelFactory) .get(MyViewModel::class.java) }
  58. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { ... } @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory<MyViewModel> } class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { ... }
  59. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { ... } @Component interface ApplicationComponent { ... val myViewModel: MyViewModel } class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { ... }
  60. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  61. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  62. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  63. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  64. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  65. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  66. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  67. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java)
  68. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java) inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: () -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java) private val myViewModel by lazy { getViewModel { injector.myViewModel } }
  69. inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: ()

    -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java) inline fun <reified T : ViewModel> FragmentActivity.getViewModel( crossinline provider: () -> T ) = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = provider() as T }).get(T::class.java) private val myViewModel by lazy { getViewModel { injector.myViewModel } } private val myViewModel by lazy { getViewModel { injector.myViewModel } }
  70. inline fun <reified T : ViewModel> FragmentActivity.viewModel( crossinline provider: ()

    -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } implementation 'androidx.activity:activity-ktx:1.0.0-alpha06' implementation 'androidx.fragment:fragment-ktx:1.1.0-alpha06'
  71. inline fun <reified T : ViewModel> FragmentActivity.viewModel( crossinline provider: ()

    -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } implementation 'androidx.activity:activity-ktx:1.0.0-alpha06' implementation 'androidx.fragment:fragment-ktx:1.1.0-alpha06' inline fun <reified T : ViewModel> FragmentActivity.viewModel( crossinline provider: () -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } }
  72. private val myViewModel by viewModel { injector.myViewModel } inline fun

    <reified T : ViewModel> FragmentActivity.viewModel( crossinline provider: () -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } implementation 'androidx.activity:activity-ktx:1.0.0-alpha06' implementation 'androidx.fragment:fragment-ktx:1.1.0-alpha06' inline fun <reified T : ViewModel> FragmentActivity.viewModel( crossinline provider: () -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } }
  73. class MyOtherViewModel @Inject constructor( ... ) : ViewModel() { ...

    } @Component interface ApplicationComponent { ... val myOtherViewModel: MyOtherViewModel }
  74. private val myOtherViewModel by viewModel { injector.myOtherViewModel } class MyOtherViewModel

    @Inject constructor( ... ) : ViewModel() { ... } @Component interface ApplicationComponent { ... val myOtherViewModel: MyOtherViewModel }
  75. inline fun <reified T : ViewModel> Fragment.viewModel( crossinline provider: ()

    -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } inline fun <reified T : ViewModel> Fragment.activityViewModel( crossinline provider: () -> T ) = activityViewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } }
  76. inline fun <reified T : ViewModel> Fragment.viewModel( crossinline provider: ()

    -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } inline fun <reified T : ViewModel> Fragment.activityViewModel( crossinline provider: () -> T ) = activityViewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } inline fun <reified T : ViewModel> Fragment.viewModel( crossinline provider: () -> T ) = viewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } } inline fun <reified T : ViewModel> Fragment.activityViewModel( crossinline provider: () -> T ) = activityViewModels<T> { object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>) = factory() as T } }
  77. private val myViewModel by viewModel { injector.myViewModel } private val

    mySharedViewModel by activityViewModel { injector.myViewModel }
  78. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { lateinit var message: String ... } viewModel.message = intent.getStringExtra(EXTRA_MESSAGE)
  79. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) :

    ViewModel() { lateinit var message: String ... } viewModel.message = intent.getStringExtra(EXTRA_MESSAGE) ❌
  80. class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner, private val

    message: String ) : ViewModel() { ... } AssistedInject class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner, private val message: String ) : ViewModel() { ... }
  81. class MyViewModel @AssistedInject constructor( private val businessRunner: BusinessRunner, @Assisted private

    val message: String ) : ViewModel() { @AssistedInject.Factory interface Factory { fun create(message: String): MyViewModel } ... }
  82. @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModel.Factory } private

    val myViewModel by viewModel { injector.myViewModel } private val viewModel by viewModel { injector.myViewModelFactory.create( message = intent.getStringExtra(EXTRA_MESSAGE) ) } private val myViewModel by viewModel { injector.myViewModel }
  83. @AssistedModule @Module(includes = [AssistedInject_AssistedInjectModule::class]) interface AssistedInjectModule @AssistedModule @Module(includes = [AssistedInject_ApplicationModule::class])

    object ApplicationModule { ... } @AssistedModule @Module(includes = [AssistedInject_AssistedInjectModule::class]) interface AssistedInjectModule
  84. #1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid

    member injection #4 Always go for static @Provide methods Tips
  85. #1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid

    member injection #4 Always go for static @Provide methods #5 Use the new @Component.Factory Tips
  86. #1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid

    member injection #4 Always go for static @Provide methods #5 Use the new @Component.Factory #6 Control scope with ViewModels Tips
  87. #1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid

    member injection #4 Always go for static @Provide methods #5 Use the new @Component.Factory #6 Control scope with ViewModels #7 Take advantage of AssistedInject Tips
  88. #1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid

    member injection #4 Always go for static @Provide methods #5 Use the new @Component.Factory #6 Control scope with ViewModels #7 Take advantage of AssistedInject Tips #1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid member injection #4 Always go for static @Provide methods #5 Use the new @Component.Factory #6 Control scope with ViewModels #7 Take advantage of AssistedInject
  89. References That Missing Guide: How to use Dagger2 By Gabor

    Varadi Keeping the Daggers Sharp ⚔ by Py
  90. References Dagger user's guide & semantics The Future of Dependency

    Injection with Dagger 2 by Jake Wharton Helping Dagger Help You by Jake Wharton Optimizing Dagger on Android by Ron Shapiro Dagger 2 by Gregory Kick Understanding Dagger 2's Generated Code by Ron Shapiro & David P. Baker Understanding Dagger 2's Codegen implementation by Gregory Kick The only Android ViewModel Factory you'll need with Dagger (by Elforama) ViewModelProviders with Dagger 2 (answer by Gabor Varadi)
  91. References Dagger user's guide & semantics The Future of Dependency

    Injection with Dagger 2 by Jake Wharton Helping Dagger Help You by Jake Wharton Optimizing Dagger on Android by Ron Shapiro Dagger 2 by Gregory Kick Understanding Dagger 2's Generated Code by Ron Shapiro & David P. Baker Understanding Dagger 2's Codegen implementation by Gregory Kick The only Android ViewModel Factory you'll need with Dagger (by Elforama) ViewModelProviders with Dagger 2 (answer by Gabor Varadi)
  92. References Dagger and the shiny new @Component.Factory Yet another way

    to bind instances Dagger Assisted Injection The missing piece in your Dagger setup Dagger 2 on Android: The Official Guidelines You Should Be Following Learn how to make Dagger's life easier Dagger 2 on Android: The Simple Way It’s complicated, but only if you really want to