Android Dagger2: How to create and retrieve object (Kotlin)

How to Provide and Inject

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:

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.