Introduction
In this tutorial, we’ll take a look at Dagger 2 — a fast and lightweight dependency injection framework.
The framework is available for both Java and Android, but the high performance derived from compile-time injection makes it a leading solution for the latter.
Why we need it?
- Simplifies access to shared instances: It provides a simple way to obtain references to shared instances, for example once we declare in Dagger our singleton instances such as
SharedPrefrences
then we can declare fields with a simple@Inject
annotation. - Easier unit and integration testing: We can easily swap out modules that make network responses and mock out this behavior.
Dagger 2 uses the following annotations
- Provider:- classes with annotated with @Module is responsible for providing an object which can be injected.
- Consumer:- The @Inject annotation is used to defining a dependency
- Connector:- A @Component annotated interface defines the connection between the provider and consumer.
Injection with Dagger in 4 simple steps in Android using Kotlin.
Step 1: In `app/build.gradle`, apply ‘kotlin-kapt’ and import the dagger libraries
apply plugin: 'kotlin-kapt'
…
dependencies {
…
final dagger_version = '2.17'
implementation "com.google.dagger:dagger:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"
compileOnly 'javax.annotation:javax.annotation-api:1.3.2'
}
Step 2: Create an object you would like to inject by using the keyword @Inject
import javax.inject.Inject
class Info @Inject constructor() {
var text = "Hello"
}
Step 3: Declare where you are injecting to. In this case, it will be MainActivity.
import dagger.Component
// The Component is declaring what and where to inject.
// A Component should always be an interface.
// Dagger will generate a class Add `Dagger` in front of the component name, DaggerAppComponent in this case.
@Component
interface AppComponent {
// You can name it anything, such as `poke()`. It doesn't have to be `inject()`
fun inject(activity: MainActivity)
}
Step 4: Inject the objects into your MainActivity
DaggerAppComponent will first show up in red as a compile error. Simply build the project and Dagger will generate it for you.
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.myTextView
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
@Inject lateinit var info: Info
override fun onCreate(savedInstanceState: Bundle?) {
DaggerAppComponent.builder().build().inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myTextView.text = info.text
}
}
There you go! The simplest Dagger example you will ever find.
Just a little bit more info
You often only want a single copy of an object. To do that, simple add `@Singleton` in front of the class and the component. This will ensure only one copy of `Into` exist per `DaggerAppComponent` that’s built.
import dagger.Component
import javax.inject.Singleton
// The Component is declaring what and where to inject.
// A Component should always be an interface.
// Dagger will generate a class Add `Dagger` in front of the component name, DaggerAppComponent in this case.
@Singleton
@Component
interface AppComponent {
// You can name it anything, such as `poke()`. It doesn't have to be `inject()`
fun inject(activity: MainActivity)
}
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class Info @Inject constructor() {
var text = "Hello"
}
Next, create a `DaggerAppComponent` object at the global level.
var component: AppComponent = DaggerAppComponent.builder().build()
Now, you will see the same Info object being injected.
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.myTextView1
import kotlinx.android.synthetic.main.activity_main.myTextView2
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
@Inject lateinit var info1: Info
@Inject lateinit var info2: Info
override fun onCreate(savedInstanceState: Bundle?) {
component.inject(this) // Having a component at global level ensure that Info is Singleton across the app.
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
info1.text = "Hello One"
info2.text = "Hello Two"
myTextView1.text = info1.text
myTextView2.text = info2.text
// Both myTextView1 and myTextView2 will display "Hello Two"
}
}
Now this is a just simple example of a dagger there are many more uses of a dagger but as a newbie, this will help us. Just consider it as hands-on Dagger
Keep Coding !!