Dagger2 – Providing
Object’s by tagging Constructor with @Inject tutorial
Welcome to lesson 2. Let’s continue on using
dagger2 by using our lesson 1 example of butter and sandwiches in http://j2emanue.blogspot.com/
In Dagger2 we can provide
dependencies using modules registered in components. This much we know from
lesson 1. Dagger2 also allows for
providing an object by tagging its constructor with @Inject.
Let’s take our story from
lesson 1 further and say now we want to add a utensil to the story. A knife for our spread. So Let’s create a knife class. My directory
structure will now look like this after creating a utensils package:
The Knife.java class itself
will look like this:
public class Knife { int count=0; @Inject public Knife(){ System.out.println("a spreading knife has been created"); }; @Override public String toString() { return "Knife{" + "count=" + ++count + '}'; } }
What I’m about to show you is
how we can inject knife into our mainActivity without putting it in any module.
We wont reference it in any component either.
Placing @Inject on a constructor
makes it detectable to Dagger2. Notice that our knife constructor is annotated
with @Inject. It becomes automatically
unscoped but ready to be injected into our mainactivity. Let’s see what our
mainActivity would look like now that we have a knife:
Actually we have two knife classes which are injected. Once we have a component build in onCreate(), those classes become available to us.public class MainActivity extends AppCompatActivity { private final String TAG = getClass().getSimpleName(); //@Inject //AlmondButter someAlmondButter; @Inject CashewSandwich sandwich; @Inject CashewSandwich sandwich2; @Inject Knife mKnife; @Inject Knife mKnife2; SandwichComponent sandwichComponent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /*create the dependent butter for the sandwich here*/ ButterComponent butterComponent = DaggerButterComponent.builder(). butterModule(new ButterModule()).build(); /*create a scope sandwichcomponent here */ sandwichComponent = DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()). butterComponent(butterComponent) .build(); //finally we have a sandwichComponent, lets inject our dependencies sandwichComponent.inject(this); Log.v(TAG, " first:" + sandwich.toString()); Log.v(TAG, "second:" + sandwich2.toString()); Log.v(TAG, "first knife:" + mKnife.toString()); Log.v(TAG, "second knife" + mKnife2.toString()); } }
Keep in mind, the knife class
is unscoped right now. That means, each time we call @inject to supply us with
a knife, we are creating a brand new object. If we wanted to keep the same
object we would use the scope of the component (in our case @SandwichScope) and
mark the class (NOT the constructor) with this scope. Lets see how we can make
our knife.java class scoped:
@SandwitchScope public class Knife { int count=0; @Inject public Knife(){ System.out.println("a spreading knife has been created"); }; @Override public String toString() { return "Knife{" + "count=" + ++count + '}'; } }
Notice the top line has a
scope annotation. This makes our knife class be a singleton within the
sandwichScope. Since our component in mainactivity
is a sandwichComponent tagged with @SandwichScope, the knife object becomes a
singleton for as long as this component exists.
I hope this information was
informative.
In conclusion I would think modules and components to provide objects is a more cleaner way of organizing your project then marking a constructor with @Inject. It would be difficult to know a class is provided easily otherwise. Why ? You would have to search your code base under each class and find out which one has a constructor with @Inject. Thats a code smell. With modules we can simply search the module file to find all providers (especially if modules are package specific).
In conclusion I would think modules and components to provide objects is a more cleaner way of organizing your project then marking a constructor with @Inject. It would be difficult to know a class is provided easily otherwise. Why ? You would have to search your code base under each class and find out which one has a constructor with @Inject. Thats a code smell. With modules we can simply search the module file to find all providers (especially if modules are package specific).
If I have seen further than
others, it is by standing upon the shoulders of giants. - Isaac Newton
In case of field injection do we have to register in components?
ReplyDeleteyes field injection should come from components. but constructor injection can bypass component registration. field injection should come from a class that is registered in a component.
ReplyDelete