This article assume you already know the basic of dagger2.
This article shall focus on
- Provide: ways to create instances to be injected
- Inject: how to inject instances into Activity, Fragment, Classes, Fields vs Constructor
NOTE: I am still a noob with Dagger2, so I might miss out something.
Provide / Create Object
Ways to create instances to be injected.
Instantiate Service with @Module and @Provides
This method is commonly used to instantiate singleton services/objects such as Database, Json parser (Gson/Moshi), Network/Retrofit API object, SharedPreferences, etc.
@Moduleinternal class AppModule { @Singleton @Provides fun provideDatabase(app: Application): AppDatabase { return Room.databaseBuilder(app, AppDatabase::class.java, "LuaPass.db") .addMigrations(MIGRATION_1_2) .build() } @Singleton @Provides fun provideMoshi(): Moshi { return Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(LocalDateTimeAdapter()) .add(MultipleFormatsDateAdapter()) .build() } @Singleton @Provides fun providePasswordDao(db: AppDatabase): PasswordDao { return db.passwordDao() } }
NOTE: Refer to this Dagger2 tutorial for a more complete sample.
NOTE: For non-singleton, you can look into Reusable scope.
Pass startup object/parameter via Binding Instances
You can use Binding Instances to pass object/paremeter during program startup (e.g. android application instance or command line arguments).
@Singleton@Component(modules = [AndroidInjectionModule::class, AppModule::class, ActivityModule::class])interface AppComponent { @Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder fun build(): AppComponent }}
class LuaApp : Application() { override fun onCreate() { super.onCreate() DaggerAppComponent.builder().application(this).build() }}
Runtime injection
Create a module to provide runtime value using singleton object as storage.
// a module to provide value via singleton object@Moduleinternal class RuntimeModule { @Provides fun provideUsername() = RuntimeInjection.username}
// singleton object as storageobject RuntimeInjection { var username: String = ""}
// Assign value to singleton object during runtimeRuntimeInjection.username = "Desmond"
NOTE: Make sure to include Module via @Module(includes = [RuntimeModule::class]) in AppModule
or @Component(modules = [..., [RuntimeModule::class]) in AppComponent
.
NOTE: If you are providing multiple values of the same type object (e.g. username and password, which are both string), use Qualifiers.
NOTE: I am not sure if this is a good practice/pattern.
Assisted injection with AutoFactory
For assisted injection (with runtime paramaters), you might want to look into AutoFactory.
Inject / Retrieve Object
Access objects via constructor @Inject, fields @Inject or access value from dagger component.
Constructor @Inject
class PasswordViewModel @Inject constructor(private val dataSource: PasswordDao, private val categoryDataSource: CategoryDao) : ViewModel() {}
NOTE: Refer to Inject ViewModel into Activity.
class Foo @Inject constructor (private val bar: Bar) { }
NOTE: Refer to Injection for basic classes (for non-Activity/Fragment class).
Fields @Inject
Sometimes we are not responsible for object instantation (e.g. Activity, Fragment, WorkManager, etc), thus fields injection is required.
class MainActivity : AppCompatActivity() { @Inject lateinit var moshi: Moshi @Inject lateinit var sharedPref: SharedPreferences @Inject lateinit var viewModelFactory: ViewModelFactory}
NOTE: Refer to Activity Injection.
NOTE: Refer to Fragment Injection.
NOTE: Refer to Injection for basic classes (for non-Activity/Fragment class).
Component Getter
@Singleton@Component(...)interface AppComponent { ... fun getMoshi(): Moshi}
val component = DaggerAppComponent.builder().build()val moshi = component.getMoshi()
NOTE: Refer to Alternative To Dagger Static Injection Using Component Getter for a full sample.
References: