Slide 1

Slide 1 text

It's complicated, but it doesn't have to be: a Dagger journey ⚔ Fred Porciúncula @tfcporciuncula

Slide 2

Slide 2 text

Why Dagger?

Slide 3

Slide 3 text

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 get(Class type); public abstract 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 get(); } public interface MembersInjector { void injectMembers(T instance); } " From The Future of Dependency Injection with Dagger 2 by Jake Wharton

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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(); } ⚔

Slide 6

Slide 6 text

Compile time safety Scalability Performance No boilerplate

Slide 7

Slide 7 text

Compile time safety Scalability Performance No boilerplate Compile time safety

Slide 8

Slide 8 text

Compile time safety Scalability Performance No boilerplate Scalability Compile time safety

Slide 9

Slide 9 text

Compile time safety Scalability Performance No boilerplate Scalability Performance Compile time safety

Slide 10

Slide 10 text

Compile time safety Scalability Performance No boilerplate # Scalability Performance No boilerplate Compile time safety

Slide 11

Slide 11 text

Project size/complexity DI verbosity/boilerplate

Slide 12

Slide 12 text

Project size/complexity DI verbosity/boilerplate ⚔ Illustration purpose, no real data *

Slide 13

Slide 13 text

Project size/complexity DI verbosity/boilerplate ⚔ Illustration purpose, no real data *

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

Modularization

Slide 21

Slide 21 text

Modularization Forging the Dagger for the modern Android world by Lorenzo Quiroli

Slide 22

Slide 22 text

Modularization Dependency injection in a multi module project by Ben Weiss

Slide 23

Slide 23 text

Slide 24

Slide 24 text

class BusinessUtil { ... }

Slide 25

Slide 25 text

class BusinessUtil { ... } class BusinessRunner( private val businessUtil: BusinessUtil ) { ... }

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Constructor injection FTW Tip #1 Go with construction injection for all classes you own

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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 ) { ... }

Slide 31

Slide 31 text

@Singleton is expensive Tip #2 Avoid unnecessary scoping and favor @Reusable instances

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

@Component interface ApplicationComponent { }

Slide 34

Slide 34 text

@Singleton @Component interface ApplicationComponent { }

Slide 35

Slide 35 text

@Singleton @Component interface ApplicationComponent { } @Component interface ApplicationComponent { val businessRunner: BusinessRunner }

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

@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()

Slide 40

Slide 40 text

@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 }

Slide 41

Slide 41 text

@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)

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

@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)

Slide 44

Slide 44 text

@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)

Slide 45

Slide 45 text

@Component interface ApplicationComponent { val businessRunner: BusinessRunner }

Slide 46

Slide 46 text

@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) }

Slide 47

Slide 47 text

@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) }

Slide 48

Slide 48 text

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 ... }

Slide 49

Slide 49 text

class MainActivity : AppCompatActivity() { @Inject lateinit var viewModel: MyViewModel ... }

Slide 50

Slide 50 text

class MainActivity : AppCompatActivity() { @Inject lateinit var viewModel: MyViewModel private val viewModel = component.myViewModel ... }

Slide 51

Slide 51 text

Avoid member injection Tip #3 Favor exposing dependencies in the components

Slide 52

Slide 52 text

@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

Slide 53

Slide 53 text

@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

Slide 54

Slide 54 text

@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 ) { ... }

Slide 55

Slide 55 text

class MyApplication : Application() { }

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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() { }

Slide 59

Slide 59 text

class MyApplication : Application() { val component by lazy { DaggerApplicationComponent.create() } }

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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 }

Slide 64

Slide 64 text

External classes

Slide 65

Slide 65 text

@Module object SharedPreferencesModule { }

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

@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 { ... }

Slide 68

Slide 68 text

@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 { ... }

Slide 69

Slide 69 text

Always go for static @Provide methods Tip #4 No one wants your module instance

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

@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 { }

Slide 72

Slide 72 text

Context

Slide 73

Slide 73 text

@Component(modules = [ApplicationModule::class]) interface ApplicationComponent { ... }

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

@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)

Slide 77

Slide 77 text

@Component interface ApplicationComponent { ... }

Slide 78

Slide 78 text

@Component interface ApplicationComponent { ... } @Component.Builder interface Builder { } ... }

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

@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 } ... }

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

@Component interface ApplicationComponent { ... }

Slide 83

Slide 83 text

@Component interface ApplicationComponent { ... } @Component interface ApplicationComponent { @Component.Factory interface Factory { }

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

interface Factory { fun create( @BindsInstance applicationContext: Context ): ApplicationComponent } ... } DaggerApplicationComponent .factory() .create(applicationContext)

Slide 86

Slide 86 text

Use the new @Component.Factory Tip #5 And avoid the lame module with constructor arguments or the old @Component.Builder

Slide 87

Slide 87 text

@Inject @Singleton @Reusable @Component @Module @BindsInstance

Slide 88

Slide 88 text

@Inject @Singleton @Reusable @Component @Module @BindsInstance @Subcomponent

Slide 89

Slide 89 text

@Subcomponent

Slide 90

Slide 90 text

@Subcomponent Encapsulation

Slide 91

Slide 91 text

@Subcomponent Scoping Encapsulation

Slide 92

Slide 92 text

@Subcomponent Scoping

Slide 93

Slide 93 text

Application Component

Slide 94

Slide 94 text

Application Component Subcomponent1 Activity1 Subcomponent2 Activity2 Subcomponent3 Activity3 ...

Slide 95

Slide 95 text

dagger-android

Slide 96

Slide 96 text

dagger-android • Great for that setup

Slide 97

Slide 97 text

dagger-android • Great for that setup • Still verbose

Slide 98

Slide 98 text

dagger-android • Great for that setup • Still verbose • Real DI

Slide 99

Slide 99 text

dagger-android • Great for that setup • Still verbose • Real DI • Member injection

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

dagger-android • Great for that setup • Still verbose • Real DI • Member injection • Decouples injection sites from injector Doesn’t work with dynamic features

Slide 102

Slide 102 text

dagger-android

Slide 103

Slide 103 text

ViewModel

Slide 104

Slide 104 text

@Subcomponent $

Slide 105

Slide 105 text

class MyViewModel( private val businessRunner: BusinessRunner ) : ViewModel() { ... }

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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 create(modelClass: Class) = MyViewModel(businessRunner) as T }

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

@Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory }

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

@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) }

Slide 112

Slide 112 text

class MyViewModel( private val businessRunner: BusinessRunner ) : ViewModel() { ... }

Slide 113

Slide 113 text

class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { ... }

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

@Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory }

Slide 119

Slide 119 text

@Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory } @Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModelFactory }

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { ... }

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { ... } @Component interface ApplicationComponent { ... val myViewModel: MyViewModel } class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { ... }

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

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

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

implementation 'androidx.activity:activity-ktx:1.0.0-alpha06' implementation 'androidx.fragment:fragment-ktx:1.1.0-alpha06'

Slide 135

Slide 135 text

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

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

class MyOtherViewModel @Inject constructor( ... ) : ViewModel() { ... }

Slide 139

Slide 139 text

class MyOtherViewModel @Inject constructor( ... ) : ViewModel() { ... } @Component interface ApplicationComponent { ... val myOtherViewModel: MyOtherViewModel }

Slide 140

Slide 140 text

private val myOtherViewModel by viewModel { injector.myOtherViewModel } class MyOtherViewModel @Inject constructor( ... ) : ViewModel() { ... } @Component interface ApplicationComponent { ... val myOtherViewModel: MyOtherViewModel }

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

private val myViewModel by viewModel { injector.myViewModel } private val mySharedViewModel by activityViewModel { injector.myViewModel }

Slide 144

Slide 144 text

Control scope with ViewModels Tip #6 Take advantage of what Android gives you for free

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

component .mySubcomponentFactory() .create(intent.getStringExtra(EXTRA_MESSAGE)) .inject(this) class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner, private val message: String ) : ViewModel() { ... }

Slide 147

Slide 147 text

class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { lateinit var message: String ... }

Slide 148

Slide 148 text

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

Slide 149

Slide 149 text

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

Slide 150

Slide 150 text

class MyViewModel @Inject constructor( private val businessRunner: BusinessRunner ) : ViewModel() { lateinit var message: String ... }

Slide 151

Slide 151 text

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

Slide 152

Slide 152 text

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() { ... }

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

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

Slide 155

Slide 155 text

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

Slide 156

Slide 156 text

class MyViewModel @AssistedInject constructor( private val businessRunner: BusinessRunner, @Assisted private val message: String ) : ViewModel() { @AssistedInject.Factory interface Factory { fun create(message: String): MyViewModel } ... }

Slide 157

Slide 157 text

@Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModel.Factory }

Slide 158

Slide 158 text

@Component interface ApplicationComponent { ... val myViewModelFactory: MyViewModel.Factory } private val myViewModel by viewModel { injector.myViewModel }

Slide 159

Slide 159 text

@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 }

Slide 160

Slide 160 text

No content

Slide 161

Slide 161 text

compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0' kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'

Slide 162

Slide 162 text

@AssistedModule @Module(includes = [AssistedInject_AssistedInjectModule::class]) interface AssistedInjectModule

Slide 163

Slide 163 text

@AssistedModule @Module(includes = [AssistedInject_AssistedInjectModule::class]) interface AssistedInjectModule @AssistedModule @Module(includes = [AssistedInject_ApplicationModule::class]) object ApplicationModule { ... } @AssistedModule @Module(includes = [AssistedInject_AssistedInjectModule::class]) interface AssistedInjectModule

Slide 164

Slide 164 text

Take advantage of AssistedInject Tip #7 Assisted injection is a thing in Dagger

Slide 165

Slide 165 text

Tips

Slide 166

Slide 166 text

#1 Constructor injection FTW Tips

Slide 167

Slide 167 text

#1 Constructor injection FTW #2 @Singleton is expensive Tips

Slide 168

Slide 168 text

#1 Constructor injection FTW #2 @Singleton is expensive #3 Avoid member injection Tips

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

#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

Slide 171

Slide 171 text

#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

Slide 172

Slide 172 text

#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

Slide 173

Slide 173 text

#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

Slide 174

Slide 174 text

References That Missing Guide: How to use Dagger2 By Gabor Varadi Keeping the Daggers Sharp ⚔ by Py

Slide 175

Slide 175 text

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)

Slide 176

Slide 176 text

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)

Slide 177

Slide 177 text

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

Slide 178

Slide 178 text

bit.ly/dagger-journey

Slide 179

Slide 179 text

Thanks. bit.ly/dagger-journey @tfcporciuncula