Dagger 2 ( Caution: PLEASE TRY AT HOME ) Part 6
WOW, we got one more day so it’s time to make this day awesome by learning something new.🙂
Hello friends, hope you are doing good. So today we are going to enjoy the next part of Dagger 2 and that is part 6. This post will be very short. In this, I will discuss with you about Constructor and Method Injection by using Dagger 2. In all our previous posts, we are using field Injection. But now it’s time to explore or get benefit from Constructor and Method injections.
Motivation:
Motivation is same which I already shared with you in part 1.
Revision:
In part 1 we discussed
- What is a dependency?
- What is a dependent?
- What is a Dependency Injection ( DI )?
- Famous techniques/strategies for DI ( Constructor Injection, Method Injection, Field Injection )
- How to make a dependency graph from code.
In part 2 we discussed:
- Annotation Processing
- Magic words
- @Component, @Module, @Provide
- How to move dependencies into component
- Relationship between component and module
In part 3 we discussed:
- Refactor all dependencies from App code to Component
- Tips for “how to read the error on a console”
- @Inject Magic Keyword
- Abstraction Between AppCode and Creation Code.
In part 4 we discussed:
- Refactoring Application class dependencies from App code to AppComponent.
- Refactoring of Bad ( Wrong ) practices for Glide and GitHubRepository.
- Dependency on Components ( HomeActivityComponent dependent upon AppComponent )
- Reusability of AppComponent into child components by adding as dependencies into Component.
In part 5 we discussed:
- Why we are not able to use void inject(App app) in out AppComponent (Parent ) Component
- What is Subcomponent
- Comparision between Component and Subcomponent
- Dagger 2 generated code comparison for Component and SubComponent.
Before going to start some important points related to our code base. For this post, I am going to checkout from branch Part4WithRefactoring. But you guys can use Part5 branch. Basically today we will do a refactoring in our HomeActivity Module. So if you want to go with SubComponent approach you guys can check out from Part5Part5SubComponents. There will not be any effect of today’s topic on our approach ( Component approach or Subcomponent approach).
What is Dependency Injection?
For this, I am going to copy some information from part 1, where we already discuss Dependency Injection.
“
What is Dependency?
For example, I have two classes A and B. Now A is using B. So we can say A is dependent on B.
public class A {
B b;
public A(B b) {
this.b = b;
}
}public class B {}
Now here we can say B is a Dependency for A. I think the confusion is clear.
A -> Dependent on -> B
B-> Dependency for -> A
Just like we know in android we used to add dependencies like
compile 'com.android.support:appcompat-v7:25.3.1'
So our Android app is dependent upon appcompat lib or we can say appcompat is a dependency for our app.
What is Dependency Injection?
Here we already know what is a dependency. Now its time to check first Injection definition. How you are going to provide a Dependency on a class or a project that is called an Injection. So as a whole Dependency injection means, how I am going to provide the classes or libs on which my app or program dependent is called Dependency Injection.
There are three famous techniques to provide a dependency which I am going to mention below but will discuss later.
1. Constructor Injection (Means I am providing some code or object by using constructor, on which my class is dependent)
2. Method Injection (Means I am providing some code or object by using method, on which my class is dependent)
3. Field Injection (Means I am giving some code or object by using Field, on which my class is dependent) “
Hope everything is revised and cleared. Now it’s time to start working on Constructor Injection.
Construction Injection Dagger 2:
That is the easiest concept which I can say we are going to learn in Dagger 2. :)
So here my approach is by refactoring. I an showing you below our HomeActivityModule coce.
@Module
public class HomeActivityModule {private final Context context;public HomeActivityModule(Context context) {
this.context = context;
}@Provides
public RecyclerView.LayoutManager layoutManager() {
return new LinearLayoutManager(context);
}@Provides
public HomeAdapter homeAdapter(Glide glide) {
return new HomeAdapter(new ArrayList<>(), glide);
}@Provides
public FormatString formatString() {
return new FormatString("Hello Guys");
}
}
Here I am going to refactor this HomeAdapter provide dependency, as we know currently we are using this as a field injection. For revision our HomeActivity code.
public class HomeActivity extends AppCompatActivity {private RecyclerView recyclerView;
private ProgressBar progressBar;
private Disposable disposable;@Inject
GitHubRepository gitHubRepository;
@Inject
HomeAdapter homeAdapter;
@Inject
RecyclerView.LayoutManager layoutManager;
@Inject
FormatString formatString;
.....
}
Now in above code HomeAdapter we are using as a Field Injection. It's time to refactor this HomeAdapter to Construction Injection.
public class HomeAdapter extends RecyclerView.Adapter<HomeViewHolder> {private final Glide glide;
private LayoutInflater layoutInflater;
private Subject<GitHubUser> clickSubject;
private List<GitHubUser> gitHubUsers;public HomeAdapter(List<GitHubUser> gitHubUsers, Glide glide) {
if (gitHubUsers == null)
throw new IllegalArgumentException("List<GitHubUser> required");
this.gitHubUsers = gitHubUsers;
this.clickSubject = PublishSubject.create();
this.glide = glide;
}
.......
}
Currently, our HomeAdapter constructor looks like above code. One more important point, for now, I am removing our List<GutHubUser> param from the constructor. So you guys only do a focus on constructor injection. After removing param:
...
private List<GitHubUser> gitHubUsers = new ArrayList<>();public HomeAdapter(Glide glide) {
...
}
It's time to refactor our code for Constructor Injection.
@Inject
public HomeAdapter(Glide glide) {
this.clickSubject = PublishSubject.create();
this.glide = glide;
}
Done. Now our code is ready for constructor injection. Next, I am going to remove some code from our HomeActivityModule.
@Module
public class HomeActivityModule {private final Context context;public HomeActivityModule(Context context) {
this.context = context;
}@Provides
public RecyclerView.LayoutManager layoutManager() {
return new LinearLayoutManager(context);
}// @Provides
// public HomeAdapter homeAdapter(Glide glide) {
// return new HomeAdapter(glide);
// }@Provides
public FormatString formatString() {
return new FormatString("Hello Guys");
}
}
As you can see I comment the HomeAdapter provide code. Now if you run our app. Our app will work how it's working previously but the only difference is this time Dagger 2 will use our adapter as Constructor Injection.
That is really simple. But I think we should do a graph comparison to grasp this concept.
Field Injection ( Before refactoring to Constructor Injection):
So before Constructor injection, we are injecting HomeAdapter as shown below.
That is a simple flow. How Dagger is injecting HomeAdapter as field injection. I don't think there is any confusion. Truly saying in this case Dagger 2 is doing nothing special instead we are giving everything to Dagger 2 and then Dagger 2 only writing glue code for us.
I mostly used to say above image is, How developer sees the code.
Now it's time to show you how Dagger 2 see his code. Or you can see we are going to check Dagger 2 generated code for this field injection.
Here we review all the glue code which is written by Dagger 2 for us in case of Field Injection.
Constructor Injection:
Construction injection as a diagram shown below:
Now here is some magic. As you can see. There I am not providing HomAdapter but the code is working properly. Changes you can see easily. I added @Inject in HomeAdapter constructor and I removed @Provide from HomeActivityModule. Yes in HomeActivity I am using HomeAdapter as a field injection for this example but I am also asking to Dagger 2 please provide me that by using Constructor Injection. It's time to show you guys Dagger 2 generated code. So you can see how Constructor Injection works and how a developer can save a lot of lines of code from writing.
So above is a constructor injection. If you compare both Constructor injection and Field Injection the difference is only:
- In Field Injection I am giving Adapter by @Providing in Module
- In Constructor injection I am not writing any line of code to provide adapter except I added @Inject on the constructor of the adapter.
- If you compare both Dagger 2 generated images. You can easily see. In field injection, Dagger 2 is using our module but in case of constructor injection that is generating MembersInjector on his own.
Now my thoughts about Constructor injection. Yes, we can save a lot of code once we use in a project but one issue which I faced if someone is a newcomer, then constructor injection gave him tough time, so if you are going to use in your project and you don't have experience team members remember you need to teach them explicitly about this. Otherwise, that is really tough to figure it out how things are injecting Dagger 2.
As a bonus, I am going to show you Method injection in the Dagger 2.
Method Injection:
Here I am going to show you one simple example which I will not explain for Method Injection :) .
So you can easily see Dagger 2 is injecting Glide object for me into the method. Second, I am not calling this method (glideMethodInjection) anywhere explicitly but you can see Log. It's mean that method is called by Dagger 2 once that is trying to inject this glide object. So you can use method injection in a lot of places.
Checkout code on GitHub for part6.
Conclusion:
Today my Dagger2 series is complete. If I miss something for that I am sorry but please inform me, so I can add that also to my series. I hope you not only learn something from my series instead you also enjoy my series. So to all of my anonymous friends' BYE. Have a nice day.
Next, maybe I will start Dagger 2 for Android series. As we know there is a new version 2.14.1 which contain a lot of specific things only for Android. If you have any suggestion please share with me may be in comments or on email.