Android

Dagger 2

Syntax#

  • @Module
  • @Component(dependencies={OtherComponent.class}, modules={ModuleA.class, ModuleB.class})
  • DaggerMyComponent.create()
  • DaggerMyComponent.builder().myModule(newMyModule()).create()

Remarks#

Not to confuse with dagger by square, the predecessor to dagger 2.

Component setup for Application and Activity injection

A basic AppComponent that depends on a single AppModule to provide application-wide singleton objects.

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    void inject(App app);

    Context provideContext();

    Gson provideGson();
}

A module to use together with the AppComponent which will provide its singleton objects, e.g. an instance of Gson to reuse throughout the whole application.

@Module
public class AppModule {

    private final Application mApplication;

    public AppModule(Application application) {
        mApplication = application;
    }

    @Singleton
    @Provides
    Gson provideGson() {
        return new Gson();
    }

    @Singleton
    @Provides
    Context provideContext() {
        return mApplication;
    }
}

A subclassed application to setup dagger and the singleton component.

public class App extends Application {

    @Inject
    AppComponent mAppComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        DaggerAppComponent.builder().appModule(new AppModule(this)).build().inject(this);
    }

    public AppComponent getAppComponent() {
        return mAppComponent;
    }
}

Now an activity scoped component that depends on the AppComponent to gain access to the singleton objects.

@ActivityScope
@Component(dependencies = AppComponent.class, modules = ActivityModule.class)
public interface MainActivityComponent {

    void inject(MainActivity activity);
}

And a reusable ActivityModule that will provide basic dependencies, like a FragmentManager

@Module
public class ActivityModule {

    private final AppCompatActivity mActivity;

    public ActivityModule(AppCompatActivity activity) {
        mActivity = activity;
    }

    @ActivityScope
    public AppCompatActivity provideActivity() {
        return mActivity;
    }


    @ActivityScope
    public FragmentManager provideFragmentManager(AppCompatActivity activity) {
        return activity.getSupportFragmentManager();
    }
}

Putting everything together we’re set up and can inject our activity and be sure to use the same Gson throughout out app!

public class MainActivity extends AppCompatActivity {

    @Inject
    Gson mGson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerMainActivityComponent.builder()
                .appComponent(((App)getApplication()).getAppComponent())
                .activityModule(new ActivityModule(this))
                .build().inject(this);
    }
}

Custom Scopes

@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {
}

Scopes are just annotations and you can create your own ones where needed.

Constructor Injection

Classes without dependencies can easily be created by dagger.

public class Engine {

    @Inject // <-- Annotate your constructor.
    public Engine() {
    }
}

This class can be provided by any component. It has no dependencies itself and is not scoped. There is no further code necessary.


Dependencies are declared as parameters in the constructor. Dagger will call the constructor and supply the dependencies, as long as those dependencies can be provided.

public class Car {

    private Engine engine;

    @Inject
    public Car(Engine engine) {
        this.engine = engine;
    }
}

This class can be provided by every component iff this component can also provide all of its dependencies—Engine in this case. Since Engine can also be constructor injected, any component can provide a Car.

You can use constructor injection whenever all of the dependencies can be provided by the component. A component can provide a dependency, if

  • it can create it by using constructor injection
  • a module of the component can provide it
  • it can be provided by the parent component (if it is a @Subcomponent)
  • it can use an object exposed by a component it depends on (component dependencies)

Using @Subcomponent instead of @Component(dependencies={…})

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App app);

    Context provideContext();
    Gson provideGson();

    MainActivityComponent mainActivityComponent(ActivityModule activityModule);
}

@ActivityScope
@Subcomponent(modules = ActivityModule.class)
public interface MainActivityComponent {
    void inject(MainActivity activity);
}

public class MainActivity extends AppCompatActivity {

    @Inject
    Gson mGson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ((App)getApplication()).getAppComponent()
                .mainActivityComponent(new ActivityModule(this)).inject(this);
    }
}

How to add Dagger 2 in build.gradle

Since the release of Gradle 2.2, the use of the android-apt plugin is no longer used. The following method of setting up Dagger 2 should be used. For older version of Gradle, use the previous method shown below.

For Gradle >= 2.2

dependencies {
    // apt command comes from the android-apt plugin
    annotationProcessor 'com.google.dagger:dagger-compiler:2.8'
    compile 'com.google.dagger:dagger:2.8'
    provided 'javax.annotation:jsr250-api:1.0'
}

For Gradle < 2.2

To use Dagger 2 it’s necessary to add android-apt plugin, add this to the root build.gradle:

buildscript {
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

Then the application module’s build.gradle should contain:

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
    

android {
    …
}

final DAGGER_VERSION = '2.0.2'
dependencies {
    …

    compile "com.google.dagger:dagger:${DAGGER_VERSION}"
    apt "com.google.dagger:dagger-compiler:${DAGGER_VERSION}"
}

Reference: https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2

Creating a component from multiple modules

Dagger 2 supports creating a component from multiple modules. You can create your component this way:

@Singleton
@Component(modules = {GeneralPurposeModule.class, SpecificModule.class})
public interface MyMultipleModuleComponent {
    void inject(MyFragment myFragment);
    void inject(MyService myService);
    void inject(MyController myController);
    void inject(MyActivity myActivity);
}

The two references modules GeneralPurposeModule and SpecificModule can then be implemented as follows:

GeneralPurposeModule.java

@Module
public class GeneralPurposeModule {
    @Provides
    @Singleton
    public Retrofit getRetrofit(PropertiesReader propertiesReader, RetrofitHeaderInterceptor headerInterceptor){
        // Logic here...
        return retrofit;
    }

    @Provides
    @Singleton
    public PropertiesReader getPropertiesReader(){
        return new PropertiesReader();
    }

    @Provides
    @Singleton
    public RetrofitHeaderInterceptor getRetrofitHeaderInterceptor(){
         return new RetrofitHeaderInterceptor();
    }
}

SpecificModule.java

@Singleton
@Module
public class SpecificModule {
    @Provides @Singleton
    public RetrofitController getRetrofitController(Retrofit retrofit){
        RetrofitController retrofitController = new RetrofitController();
        retrofitController.setRetrofit(retrofit);
        return retrofitController;
    }

    @Provides @Singleton
    public MyService getMyService(RetrofitController retrofitController){
        MyService myService = new MyService();
        myService.setRetrofitController(retrofitController);
        return myService;
    }
}

During the dependency injection phase, the component will take objects from both modules according to the needs.

This approach is very useful in terms of modularity. In the example, there is a general purpose module used to instantiate components such as the Retrofit object (used to handle the network communication) and a PropertiesReader (in charge of handling configuration files). There is also a specific module that handles the instantiation of specific controllers and service classes in relation to that specific application component.


This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow