If you read first post about dependency injection, you will probably be looking for some real code. There are some beautiful examples about coffee makers at Dagger page, and an awesome model project by Jake Wharton for more experienced users. But we need something easier and coffee is not our main business model, so this article will provide an example where we are injecting some simple components to let us understand the basics.
Source code explained here can be found at DaggerExample repository at Github.
Include Dagger into your project
There are two libraries that must be added if you want to use Dagger:
[java]
dependencies {
compile fileTree(dir: ‘libs’, include: [‘*.jar’])
compile ‘com.squareup.dagger:dagger:1.2.+’
provided ‘com.squareup.dagger:dagger-compiler:1.2.+’
}
[/java]
First one is Dagger library. Second library is the dagger compiler. It will create required classes in order to be able to inject dependencies. That’s the way it can avoid most reflection, by creating precompiled classes. As we only need it to compile the project, and won’t be used by application, we mark it as provided so that it isn’t included in final apk.
Creating your first module
Modules will be your daily job with dagger, so you need to feel comfortable with them. Modules are classes that provide instances of the objects we will need to inject. They are defined by annotating the class with @Module. There are some extra parameters that may be configured, but I’ll explain when we use them.
Create a class called AppModule, that will provide, for example, the Application Context. It’s usually interesting to have an easy access to it. I created App, which extends from Application, and added to the manifest.
[java]
@Module(
injects = {
App.class
}
)
public class AppModule {
private App app;
public AppModule(App app) {
this.app = app;
}
@Provides @Singleton public Context provideApplicationContext() {
return app;
}
}
[/java]
What is new here?
@Module : identify this class as a Dagger module.
injects : Classes where this module is going to inject any of its dependencies. We need to specify those classes that are directly injected into object graph. This will be covered soon.
@Provides: Identify method as an injection provider. The name of the method doesn’t matter, it only relies on what class type is provided.
@Singleton : if it’s present, the method will return always the same instance of the object, which is far better than regular singletons. If not, everytime this type is injected, we’ll get a new instance. In this case, as we are not creating a new instance, but returning an existing one, it would be the same if we don’t annotate as singleton, but it explains better what the provider is doing. Application instance is unique.
Why regular singletons are evil
Singletons are probably the most dangerous dependencies a project can have. First of all, because due to the fact that we are not creating an instance, it’s really hard to know where we are using it, so these are “hidden dependencies”. On the other way, we have no way to mock them for testing or to substitute it with another module, so our code becomes hard to maintain, to test and to evolve. Injected singletons, on the other way, have the benefits of a singleton (a unique instance) and, as we can create new instances at any moment, it’s easier to mock and to substitute with another piece of code, by subclassing or making them implement a common interface.
We will be creating another module in a new package called domain. It’s quite useful to have (at least) a module in every architecture layer. This module will provide an analytics manager, that will throw an event when the app starts, only by showing a Toast. In a real project, this manager could call any analytics service such as Google Analytics.
[java]
@Module(
complete = false,
library = true
)
public class DomainModule {
@Provides @Singleton public AnalyticsManager provideAnalyticsManager(Application app){
return new AnalyticsManager(app);
}
}
[/java]
By identifying this module as not complete, we say that some of the dependencies in this module need to be provided by another module. That’s the case of Application, which comes from AppModule. When we require this AnalyticsManager from a dependency injection, dagger will use this method, and will detect that it needs another dependency, Application, which will be requested to the object graph (almost there!). We also need to specify this module as a library, because dagger compiler will detect that AnalyticsManager is not been used by itself or its injected classes. It’s acting as a library module for AppModule.
We will specify that AppModule will include this one, so back to previous class:
[java]
@Module(
injects = {
App.class
},
includes = {
DomainModule.class
}
)
public class AppModule {
…
}
[/java]
includes attribute is there for that purpose.
Creating the Object Graph
The object graph is the place where all these dependencies live. The object graph contains the created instances and is able to inject them to the objects we add to it.
In previous examples (AnalyticsManager) we have seen the “classic” dependency injection, where injections are passed via constructor. But we have some classes in Android (Application, Activity) where we don’t have control over constructor, so we simply need another way to inject its dependencies.
The combination of ObjectGraph creation and this direct injection is represented in App class. The main object graph is created in the Application class and it is injected in order to get its dependencies.
[java]
public class App extends Application {
private ObjectGraph objectGraph;
@Inject AnalyticsManager analyticsManager;
@Override public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(getModules().toArray());
objectGraph.inject(this);
analyticsManager.registerAppEnter();
}
private List<Object> getModules() {
return Arrays.<Object>asList(new AppModule(this));
}
}
[/java]
We specify dependencies by annotating them with @Inject. These fields must be public or default scoped, so that dagger can assign them. We create an array with our modules (we have only one, DomainModule is included in AppModule), and create an ObjectGraph with it. After it, we inject App instance manually. After that call, dependencies are injected, so we can call AnalyticsManager method.
Conclusion
Now you know the basics about Dagger. ObjectGraph and Modules are the most interesting components that must be mastered to use Dagger efficiently. There are some more tools such as lazy injections or provider injections that are explained at Dagger site, but I don’t recommend dive into them until you are fluent using what we saw here.
Don’t forget that source code is available at Github.
Next (and probably last) post about Dagger will be focused on scoped object graphs. It basically consists of creating new object graphs that lives only where its creator does. It’s common to create scoped graphs for activities.
Stay tuned via RSS or my Google+ profile.
Very nice. It’s probably worth mentioning that to create your own Application subclass you must add android:name directly to your Tab in manifest.
How do you inject your presenter with Dagger? (presenter = new LoginPresenterImpl(this);)
Or rather why aren’t you using Dagger here for injection?
That’s for next episode, it will be injected using scoped graphs.
Thank you, I’m very excited about your next episode…
Great explanation. Sometimes I have difficulties deciding what to inject via constructor and what to inject via object fields. For activities and fragments I have only one option but for other situations I do not know which approach to take. Are there any best practices on deciding what to use?
I prefer using injection via constructor because it’s easier to instantiate objects on tests, but the other way isn’t difficult either. I really can’t think of any other reason.
I got this error :
Caused by: java.lang.IllegalStateException: Module adapter for class com.antonioleiva.daggerexample.app.AppModule could not be loaded. Please ensure that code generation was run for this module.
Do you have last version of code at Github? That happens when dagger-compiler dependency is not added, but that shouldn’t be the case unless you didn’t imported the project as a gradle project. Are you using Android Studio (or IntelliJ) and gradle?
Sorry, I didn’t import the project as a gradle, but now…
http://www.noelshack.com/2014-25-1403035858-capture-du-2014-06-17-21-10-37.png
I resolve my problem, sorry for the inconvenience, and thank you very much for your help !
Great Post! I understand that dependencies are more maintainable and easily swapped out with mocks with as shown in your example. However, I have one question: what if modules have activity life-cycle callbacks such as onCreate(), onPause(), onResume() etc.. where the dependency is to be provided in each callback. So for example, if I have an activityModule, which my MainActivity depends on, however, the activityModule must be updated with appropriate context whenever onCreate, onPause, etc are called.
So I call activityModule.onResume(this); inside my activity’s onResume(). Is there an easy way to maintain these modules using dagger?
Thx for your share!
How Can I modify a exists Injected Ojbect?
Nice blog and nice series on Dagger, congratulations! Just a couple of quick questions: I have seen people using an @Inject annotation before a no-args constructor, something like:
@Inject Foo(){
}
What is the purpose of this? Does it have any effect?
Besides this, if I inject a constructor with arguments, I need to assign them to my instance variables like:
@Inject Foo(Bar bar){
this.bar = bar;
}
When I could be doing just:
public class Foo{
@Inject Bar bar;
}
I have seen you said earlier you prefer doing this for testing purposes, but cannot you do the same if you inject instance variables and override the corresponding @Provides methods? I don’t know if I am missing something here.
Again, thanks for taking time to explain these concepts in your blog – they are really constructive!
Nice article, thanks for it! The question is – how many Modules is enough? What’s the best way to group them? The question is abstract, trying to wrap my head around the concept.
Hi, Why do you have to do objectGraph.inject(this);? Thanks!
Because the AnalyticsManager isn’t available until it’s been injected into “this”
Thanks for this article. In case someone is looking for Dagger2 example, you can take a look at this sample: https://github.com/mgrzechocinski/dagger2-example
Hi,
I am getting this error
Caused by: java.lang.IllegalStateException: Errors creating object graph:
com.myproject.domain.AnalyticsManager has no injectable members. Do you want to add an injectable constructor? required by class com.myproject.App
What am I doing wrong?
Thanks for a very good tutorial !
Somehow, most of other Dagger tutorials out there, go with a plain Java sample app. Not a best choice for an Android library.
Hi, You had an interesting comment on having one module per layer in the application. I wonder how one should layer an Android application. I’m an old Spring user but I guess the conventions for an Android application may differ than the ones for a Spring server side application. For example, what is your App class ? Is that the main activity ? Is it supposed to be named as such ? Cheers,
It depends on many things. You can take a look to this implementation of clean architecture and see if it fits your needs: https://github.com/android10/Android-CleanArchitecture. That´s what I was thinking when writing those lines, but you could have the architecture you feel most comfortable with.
The App class is a subclass of Application, that is part of the Android framework. It´s the first class that is executed when your app is launched and the last one that is destroyed. Based on that, it´s normally used to create or destroy singletons, for instance.
Hey!!
Thanks for your post but for some reason I get an error when trying to run the example and can’t figure out why.
Error:(27, 8) error: No injectable members on android.app.Application. Do you want to add an injectable constructor? required by provideAnalyticsManager(android.app.Application) for com.example.franck.dagger.AppModule
Could you help?
Thx!
@Module(injects = {AppContext.class},includes = {DomainModule.class})
public class AppModule {
private AppContext app;
public AppModule(AppContext app) {
this.app = app;
}
@Provides
@Singleton
public Application provideApplication() {
return app;
}
}
Great tutorial!!
Thanks!