Dagger 2.x Manual (revised version 6):
The following steps are listed below:
1.) add Dagger to your build.gradle files:
.
// 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();
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})
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
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);
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 .