Dagger-Android-Part 5

Dheeraj Andra
MindOrks
Published in
3 min readApr 27, 2019

Welcome to the fifth and the final part of this Dagger series. I hope you had enjoyed learning concepts and implementing things till Part 4.

In this part, we are going to introduce @Inject into our application.

Until now, we have created all our classes, modules and components for preparing our required dependencies. Now it’s time to inject those prepared dependencies in our application.

As discussed in the previous part, we will be continuing working on the following project:

Firstly, let’s update our MyApplication class:

class MyApplication :Application() {

lateinit var applicationComponent: ApplicationComponent

@Inject
@field:MarutiCar
lateinit var marutiCar: Car

override fun onCreate() {
super.onCreate()

applicationComponent = DaggerApplicationComponent
.builder()
.applicationModule(ApplicationModule(this))
.build()
applicationComponent.inject(this)

Log.d("MyApplication","${marutiCar.hashCode()}: ${marutiCar.name}")

}
}

Note: Remember to add this application name in the manifest file.

.....
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:name=".MyApplication"
.....

We can observe that we are injecting the MarutiCar here. We can go back to our ApplicationComponent interface and we can observe that we are using MarutiCarModule in the list of modules defined here. Since, we have defined the provideCar() method in MarutiCarModule and its scope as Singleton, we can inject the same here.

@Provides
@Singleton
@MarutiCar
fun provideCar(car:Car) = car

The above code is from MarutiCarModule class.

Also, we are defining an applicationComponent. The DaggerApplicationComponent class is the class that is generated by Dagger implementing the ApplicationComponent interface we discussed in our Part 4 of the series. Once the project is built successfully, you can see the DaggerApplicationComponent class being generated and it looks like follows:

....
public final class
DaggerApplicationComponent implements ApplicationComponent {
private Provider<String> provideNameProvider;

private Provider<Car> carProvider;

private Provider<Car> provideCarProvider;

private DaggerApplicationComponent(MarutiCarModule marutiCarModuleParam) {

initialize(marutiCarModuleParam);
}
...

We have defined another component called ActivityComponent in Part 4. Let’s use that in our MainActivity class:

class MainActivity : AppCompatActivity() {

lateinit var activityComponent: ActivityComponent

@Inject
@field:MarutiCar
lateinit var marutiCar: Car

@Inject
@field:ToyotaCar
lateinit var toyotaCar: Car

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

activityComponent = DaggerActivityComponent
.builder()
.applicationComponent((application as MyApplication).applicationComponent)
.activityModule(ActivityModule(this))
.build()

activityComponent.inject(this)

Log.d("MainActivity: ", "${marutiCar.hashCode()}: ${marutiCar.name}")
Log.d("MainActivity: ", "${toyotaCar.hashCode()}: ${toyotaCar.name}")

@SuppressLint("SetTextI18n")
tv_displayName.text = "${marutiCar.name}, ${toyotaCar.name}"

}
}

Exercise: What happens if we remove the @field from both toyotaCar and marutiCar. Give it a try!

We have included our ToyotaCarModule in our ActivityComponent, and, we are providing the car in the ToyotaCarModule class.

@Provides
@ActivityScope
@ToyotaCar
fun provideCar(car: Car) = car

The above code is from ToyotaCarModule class.

Exercise: What happens if we change the scope from ActivityScope to Singleton in the above code snippet? Just give it a try, change and compile it!

We have a layout file, activity_main.xml as follows:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:id="@+id/tv_displayName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>

</androidx.constraintlayout.widget.ConstraintLayout>

The textview will display the names of the variables marutiCar and toyotaCar.

That’s it! You’ve done it. Compile it and run the application. See the names of the cars on your screen!

Photo by Jason Hogan on Unsplash

Now, let’s do the exercise parts, let’s play with the application. Try to explore on the results which will give us a much better knowledge of Dagger. Please share your observations in the comments below.

Go through the Dagger classes that are generated for the Components defined. You will have a clear working knowledge of the methods that are declared in the Components and Dagger.

For example, the inject method of the DaggerActivityComponent is defined as follows in the Dagger class generated for this Component:

@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}

@Override
public Car getCar() {
return provideCarProvider.get();
}

private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMarutiCar(
instance,
Preconditions.checkNotNull(
applicationComponent.getCar(),
"Cannot return null from a non-@Nullable component method"));
MainActivity_MembersInjector.injectToyotaCar(instance, provideCarProvider.get());
return instance;
}

That’s how the required dependencies are provided by injecting the required methods in the Components.

That’s it for part 5 of the Dagger series. We have reached the end.

I sincerely thank you for your time and appreciate you, reaching all the way here.

I hope, this Dagger series is of some use. All the best.

Let’s connect on Twitter and LinkedIn

--

--