How to configure DAGGER dependency injection from scratch in an Android project?

How to use a dagger? How to set up a dagger to work in my Android project?

I would like to use Dagger in my Android project, but I find this confusing.

EDIT: Dagger2 has also been out since 2015 04 15, and it's even more confusing!

[This question is a "stub" to which I add my answer when I learned more about Dagger1 and learned more about Dagger2. This question is more of a guide than a question.]

+81
android dependency-injection dagger dagger-2
Nov 20 '14 at 10:13
source share
2 answers

Dagger 2.x Manual (revised version 6):

The following steps are listed below:

1.) add Dagger to your build.gradle files:

  • top level build.gradle :

.

 // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //added apt for source code generation } } allprojects { repositories { jcenter() } } 
  • Build.gradle application level :

.

 apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation android { compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "your.app.id" minSdkVersion 14 targetSdkVersion 24 versionCode 1 versionName "1.0" } buildTypes { debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:24.2.1' compile 'com.google.dagger:dagger:2.7' //dagger itself provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency } 

2.) Create your AppContextModule class that provides dependencies.

 @Module //a module could also include other modules public class AppContextModule { private final CustomApplication application; public AppContextModule(CustomApplication application) { this.application = application; } @Provides public CustomApplication application() { return this.application; } @Provides public Context applicationContext() { return this.application; } @Provides public LocationManager locationService(Context context) { return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); } } 

3.) create an AppContextComponent class that provides an interface for receiving injection classes.

 public interface AppContextComponent { CustomApplication application(); //provision method Context applicationContext(); //provision method LocationManager locationManager(); //provision method } 

3.1.) . How do you create a module with an implementation:

 @Module //this is to show that you can include modules to one another public class AnotherModule { @Provides @Singleton public AnotherClass anotherClass() { return new AnotherClassImpl(); } } @Module(includes=AnotherModule.class) //this is to show that you can include modules to one another public class OtherModule { @Provides @Singleton public OtherClass otherClass(AnotherClass anotherClass) { return new OtherClassImpl(anotherClass); } } public interface AnotherComponent { AnotherClass anotherClass(); } public interface OtherComponent extends AnotherComponent { OtherClass otherClass(); } @Component(modules={OtherModule.class}) @Singleton public interface ApplicationComponent extends OtherComponent { void inject(MainActivity mainActivity); } 

Beware:. You need to provide the @Scope annotation (for example, @Singleton or @ActivityScope ) in the @Provides module of the annotated method to get the provider with the scope inside your generated component, otherwise it will not be refined, and every time you enter it, you get a new copy.

3.2.) Create a component with an application area that indicates what you can enter (this is the same as injects={MainActivity.class} in dagger 1.x):

 @Singleton @Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods void inject(MainActivity mainActivity); } 

3.3.) . For dependencies that you can create using the constructor yourself and don’t want to override them using @Module (for example, you use assembly modifications instead to change the type of implementation), you can use the @Inject constructor annotated.

 public class Something { OtherThing otherThing; @Inject public Something(OtherThing otherThing) { this.otherThing = otherThing; } } 

Also, if you use the @Inject constructor, you can use field injection without explicitly calling component.inject(this) :

 public class Something { @Inject OtherThing otherThing; @Inject public Something() { } } 

These @Inject constructor classes @Inject automatically added to the component of the same scope without the need to explicitly specify them in the module.

A @Singleton class The @Inject constructor class will be displayed in @Singleton components with scope.

 @Singleton // scoping public class Something { OtherThing otherThing; @Inject public Something(OtherThing otherThing) { this.otherThing = otherThing; } } 

3.4.) After you have defined a specific implementation for this interface, for example:

 public interface Something { void doSomething(); } @Singleton public class SomethingImpl { @Inject AnotherThing anotherThing; @Inject public SomethingImpl() { } } 

You need to "bind" a specific implementation to an interface using @Module .

 @Module public class SomethingModule { @Provides Something something(SomethingImpl something) { return something; } } 

Briefly for this, since Dagger 2.4 is as follows:

 @Module public abstract class SomethingModule { @Binds abstract Something something(SomethingImpl something); } 

4.) create an Injector class to process your component at the application level (it replaces the monolithic ObjectGraph )

(note: Rebuild Project to create a DaggerApplicationComponent constructor class using APT)

 public enum Injector { INSTANCE; ApplicationComponent applicationComponent; private Injector(){ } static void initialize(CustomApplication customApplication) { ApplicationComponent applicationComponent = DaggerApplicationComponent.builder() .appContextModule(new AppContextModule(customApplication)) .build(); INSTANCE.applicationComponent = applicationComponent; } public static ApplicationComponent get() { return INSTANCE.applicationComponent; } } 

5.) create a CustomApplication class

 public class CustomApplication extends Application { @Override public void onCreate() { super.onCreate(); Injector.initialize(this); } } 

6.) add CustomApplication to your AndroidManifest.xml .

 <application android:name=".CustomApplication" ... 

7.) Add your classes to MainActivity

 public class MainActivity extends AppCompatActivity { @Inject CustomApplication customApplication; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Injector.get().inject(this); //customApplication is injected from component } } 

8.) Enjoy!

+1.) . You can specify Scope for your components, with which you can create components at the action level . Subprograms allow you to provide dependencies that you only need for a given subtype, and not for the entire application. As a rule, each activity receives its own module with this setting. Note that a restricted provider exists for each component , which means that in order to save an instance for this action, the component itself must survive a configuration change. For example, it can survive through onRetainCustomNonConfigurationInstance() or the mortar area.

For more information on copying, see the guide from Google . Also see this site for support methods , as well as the component dependency section) here .

To create a custom scope, you must specify the scope qualifier annotation:

 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface YourCustomScope { } 

To create a subclass, you need to specify the scope on your component and specify ApplicationComponent as its dependency. Obviously, you also need to specify a subclass for the module provider methods.

 @YourCustomScope @Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class}) public interface YourCustomScopedComponent extends ApplicationComponent { CustomScopeClass customScopeClass(); void inject(YourScopedClass scopedClass); } 

and

 @Module public class CustomScopeModule { @Provides @YourCustomScope public CustomScopeClass customScopeClass() { return new CustomScopeClassImpl(); } } 

Please note that only component one can be specified as a dependency. Think about it in the same way that multiple inheritance is not supported in Java.

+2.) About @Subcomponent : essentially, the @Subcomponent area can replace component dependency; but instead of using the builder created by the annotation processor, you will need to use the factory component.

So this is:

 @Singleton @Component public interface ApplicationComponent { } @YourCustomScope @Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class}) public interface YourCustomScopedComponent extends ApplicationComponent { CustomScopeClass customScopeClass(); void inject(YourScopedClass scopedClass); } 

Becomes as follows:

 @Singleton @Component public interface ApplicationComponent { YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule); } @Subcomponent(modules={CustomScopeModule.class}) @YourCustomScope public interface YourCustomScopedComponent { CustomScopeClass customScopeClass(); } 

And this:

 DaggerYourCustomScopedComponent.builder() .applicationComponent(Injector.get()) .customScopeModule(new CustomScopeModule()) .build(); 

Becomes as follows:

 Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule()); 

+3.): Please check other questions regarding Dagger2, they provide a lot of information. For example, my current Dagger2 structure is listed in this answer .

thank

Thanks for the tutorial on Github , TutsPlus , Joe Steele , Froger MCS, and Google .

Also for this is the walkthrough on migration that I found after writing this post.

And for clarification on the types of Cyril.

More information in the official documentation .

+161
Apr 29 '15 at 12:11
source share

Manual for Dagger 1.x :

The following steps are listed below:

1.) add Dagger to build.gradle file for dependencies

 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) ... compile 'com.squareup.dagger:dagger:1.2.2' provided 'com.squareup.dagger:dagger-compiler:1.2.2' 

Also add packaging-option to prevent duplicate APKs .

 android { ... packagingOptions { // Exclude file to avoid // Error: Duplicate files during packaging of APK exclude 'META-INF/services/javax.annotation.processing.Processor' } } 

2.) create an Injector class to handle the ObjectGraph .

 public enum Injector { INSTANCE; private ObjectGraph objectGraph = null; public void init(final Object rootModule) { if(objectGraph == null) { objectGraph = ObjectGraph.create(rootModule); } else { objectGraph = objectGraph.plus(rootModule); } // Inject statics objectGraph.injectStatics(); } public void init(final Object rootModule, final Object target) { init(rootModule); inject(target); } public void inject(final Object target) { objectGraph.inject(target); } public <T> T resolve(Class<T> type) { return objectGraph.get(type); } } 

3.) Create a RootModule to bundle your future modules together. Note that you must specify injects to indicate each class in which you will use the @Inject annotation, because otherwise the dagger throws a RuntimeException .

 @Module( includes = { UtilsModule.class, NetworkingModule.class }, injects = { MainActivity.class } ) public class RootModule { } 

4.) If you have other submodules inside your modules specified in the root, create modules for them:

 @Module( includes = { SerializerModule.class, CertUtilModule.class } ) public class UtilsModule { } 

5.) create leaf modules that receive dependencies as constructor parameters. In my case, there was no circular dependence, so I don’t know if the dagger can resolve this, but I find it unlikely. Designer parameters should also be provided in the module using a dagger, if you specify complete = false , then it can also be in other modules.

 @Module(complete = false, library = true) public class NetworkingModule { @Provides public ClientAuthAuthenticator providesClientAuthAuthenticator() { return new ClientAuthAuthenticator(); } @Provides public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator) { return new ClientCertWebRequestor(clientAuthAuthenticator); } @Provides public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor) { return new ServerCommunicator(clientCertWebRequestor); } } 

6.) Extend Application and initialize Injector .

 @Override public void onCreate() { super.onCreate(); Injector.INSTANCE.init(new RootModule()); } 

7.) In your MainActivity call the Injector in the onCreate() method.

 @Override protected void onCreate(Bundle savedInstanceState) { Injector.INSTANCE.inject(this); super.onCreate(savedInstanceState); ... 

8.) Use @Inject in MainActivity .

 public class MainActivity extends ActionBarActivity { @Inject public ServerCommunicator serverCommunicator; ... 

If you get a no injectable constructor found error message, make sure you don't forget @Provides annotations.

+10
Nov 20 '14 at 10:13
source share



All Articles