To understand the concept we use an example where a Car class depends on an Engine class.
1/ Create A New Project.
2/ Modify build.gradle.kts (app level)
add -> id("kotlin-kapt") on plugins top of the file
add -> below two dependency
implementation("com.google.dagger:dagger:2.51.1")
kapt("com.google.dagger:dagger-compiler:2.51.1")
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("kotlin-kapt")
}
android {
namespace = "com.zissofworks.dependencyinjectionwithdagger2"
compileSdk = 35
defaultConfig {
applicationId = "com.zissofworks.dependencyinjectionwithdagger2"
minSdk = 28
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation("com.google.dagger:dagger:2.51.1")
kapt("com.google.dagger:dagger-compiler:2.51.1")
}
3/ Create a class Engine with @Inject annotation
package com.zissofworks.dependencyinjectionwithdagger2
import android.util.Log
import javax.inject.Inject
class Engine @Inject constructor() {
fun start(){
Log.d("Dagger2Example", "Engine Start")
}
}
4/ Create a class Car with @Inject annotation and this class is dependent on the Engine class taking the Engine class object as a parameter
package com.zissofworks.dependencyinjectionwithdagger2
import android.util.Log
import javax.inject.Inject
class Car @Inject constructor(private val engine: Engine) {
fun drive(){
engine.start()
Log.d("Dagger2Example", "car drive")
}
}
5/ Create a class AppModule with @Module Annotation. This class provides the dependencies
package com.zissofworks.dependencyinjectionwithdagger2
import dagger.Module
import dagger.Provides
@Module
class AppModule {
@Provides
fun provideEngine(): Engine = Engine()
@Provides
fun provideCar(engine: Engine) : Car = Car(engine)
}
6/ Create a Component interface with @Component Annotation. The component class works as a bridge between @Inject and @Module. This class decides where the dependencies should be injected.
package com.zissofworks.dependencyinjectionwithdagger2
import dagger.Component
import javax.inject.Singleton
@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
}
7/ Create a class MyApplication which extends the Application and initializes the Component. For globally accessible Dagger Component we use this class and add on manifest
package com.zissofworks.dependencyinjectionwithdagger2
import android.app.Application
class MyApplication : Application() {
lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.builder().build()
}
}
8/ Add the MyApplication in AndroidManifest.xml file application tag
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DependencyInjectionWithDagger2"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
9/ Modify MainActivity.Kt
here we just add the variable for the Car object and never initialize or create the object. Dagger will provide the instance of Car by the @Inject annotation. We don't need to do it manually.
appComponent.inject(this) connects the activity with the component
package com.zissofworks.dependencyinjectionwithdagger2
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
@Inject
lateinit var car: Car
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
(application as MyApplication).appComponent.inject(this)
car.drive()
}
}